Как я могу реализовать конструктор и оператор перемещения для unique_ptr как закрытый член класса

Я пытаюсь написать класс Matrix. Я использую unique_ptr в качестве массива указателей хранилища. Но этот unique_ptr является закрытым членом класса. Я хочу добавить конструктор перемещения в свой класс Matrix. Но мне нужна функция getter для частного unique_ptr, но когда я возвращаю unique_ptr в качестве переменной const, я не могу использовать std :: move, но когда я возвращаю функцию getter без ссылки const, компилятор не Не допускаю этого.

Matrix.hpp

template <typename _T>
    class Matrix_
    {
    private:
        size_t rows_;
        size_t cols_;
        size_t size_;
        std::unique_ptr<_T[]> data_;        
    public:
        Matrix_();
        Matrix_(const Matrix_& _m); //Copy constructor
        Matrix_(Matrix_&& _m) noexcept; //Move constructor
        Matrix_(const size_t& rows);
        Matrix_(const size_t& rows,const size_t& cols);
        Matrix_(const size_t& rows,const size_t& cols,const _T& val);
        //Operators        
        Matrix_& operator=(const Matrix_& _m); //Copy assignment
        Matrix_& operator=(Matrix_&& _m) noexcept; //Move assignment
        //
        //Methods
        size_t getRows()const;
        size_t getCols()const;
        size_t getSize()const;
        const std::unique_ptr<_T[]>& getData()const;
        void copyData(const std::unique_ptr<_T[]>& _data);

        void fill(const _T& val);
        //
        ~Matrix_();
    };
    template <typename _T>
    Matrix_<_T>::Matrix_():rows_(1),cols_(1),size_(rows_*cols_),data_(std::make_unique<_T[]>(size_))
    {
    }
    template <typename _T>
    Matrix_<_T>::Matrix_(const Matrix_& _m):rows_(_m.getRows()),cols_(_m.getCols()),size_(rows_*cols_),data_(std::make_unique<_T[]>(size_))
    {
    }
    template <typename _T>
    Matrix_<_T>::Matrix_(Matrix_&& _m)noexcept:rows_(_m.getRows()),cols_(_m.getCols()),size_(rows_*cols_),data_(std::move(_m.getData()))
    {
    }
    template <typename _T>
    Matrix_<_T>::Matrix_(const size_t& rows):rows_(rows),cols_(1),size_(rows_*cols_),data_(std::make_unique<_T[]>(size_))
    {
    }
    template <typename _T>
    Matrix_<_T>::Matrix_(const size_t& rows,const size_t& cols):rows_(rows),cols_(cols),size_(rows_*cols_),data_(std::make_unique<_T[]>(size_))
    {
    }
    template <typename _T>
    Matrix_<_T>::Matrix_(const size_t& rows,const size_t& cols,const _T& val):rows_(rows),cols_(cols),size_(rows_*cols_),data_(std::make_unique<_T[]>(size_))
    {
        fill(val);
    }
    //Operators
    template <typename _T>
    Matrix_<_T>& Matrix_<_T>::operator=(const Matrix_& _m)
    {   
        rows_ = _m.rows_;
        cols_ = _m.cols_;
        size_ = rows_*cols_;
        data_ = std::make_unique<_T[]>(size_);
        copyData(_m.getData());
        return *this;
    }
    template <typename _T>
    Matrix_<_T>& Matrix_<_T>::operator=(Matrix_&& _m)noexcept{
        rows_ = _m.rows_;
        cols_ = _m.cols_;
        size_ = rows_*cols_;
        data_ = std::move(_m.getData());
        return *this;
    }
    //
    //Methods
    template <typename _T>size_t Matrix_<_T>::getRows()const{return rows_;}
    template <typename _T>size_t Matrix_<_T>::getCols()const{return cols_;}
    template <typename _T>size_t Matrix_<_T>::getSize()const{return size_;}    
    template <typename _T>const std::unique_ptr<_T[]>& Matrix_<_T>::getData()const{return data_;}
    template <typename _T>void Matrix_<_T>::copyData(const std::unique_ptr<_T[]>& _data){        
        for(uint i=0;i<size_;i++){data_[i]=_data[i];}
    }
    template <typename _T>void Matrix_<_T>::fill(const _T& val){
        for(uint i=0;i<size_;i++){data_[i]=val;}
    }
    //
    template <typename _T>
    Matrix_<_T>::~Matrix_()
    {
    }

Test.cpp

int main()
{
   Matrix_<double> a(10,10,5.0);
   Matrix_<double> b(10,10);
   b = std::move(a);
   std::cout<<b.getData()[0]<<std::endl;

   return 0;
}

Ошибка

error: use of deleted function ‘std::unique_ptr<_Tp [], _Dp>& std::unique_ptr<_Tp [], _Dp>::operator=(const std::unique_ptr<_Tp [], _Dp>&) [with _Tp = double; _Dp = std::default_delete<double []>]’
         data_ = std::move(_m.getData());
         ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/7/bits/locale_conv.h:41:0,
                 from /usr/include/c++/7/locale:43,
                 from /usr/include/c++/7/iomanip:43,
                 from /home/cemo/YZlib/Examples/Test.cpp:3:
/usr/include/c++/7/bits/unique_ptr.h:654:19: note: declared here
       unique_ptr& operator=(const unique_ptr&) = delete;

person YlmzCmlttn    schedule 29.03.2020    source источник
comment
Зачем вам нужен геттер для внутреннего представления данных и кто должен быть владельцем этих данных после вызова геттера? Должен ли он по-прежнему принадлежать Matrix_ или вызывающий геттер должен стать единственным владельцем данных?   -  person Yksisarvinen    schedule 29.03.2020
comment
владелец должен быть таким же. Мне нужен получатель для доступа к элементу данных аргументов, например, «Matrix_ ‹_T› :: Matrix_ (Matrix _ && m)» Мне нужна переменная данных достижения _m   -  person YlmzCmlttn    schedule 29.03.2020
comment
Это функция member. Функции-члены имеют доступ ко всем закрытым членам класса (независимо от того, хотите ли вы получить доступ к тому же или другому объекту, класс будет одним и тем же). Вам понадобится только геттер, если вам нужно получить к нему доступ из вне класса (он же любая функция, которая не является членом Matrix_)   -  person Yksisarvinen    schedule 29.03.2020
comment
Спасибо. Я этого не знал. Но все же мне интересно, почему я не могу двигаться с помощью getData () Я возвращаю частный член в качестве ссылки   -  person YlmzCmlttn    schedule 29.03.2020
comment
Не используйте идентификатор, начинающийся с подчеркивания, за которым следует заглавная буква; они зарезервированы для реализации. Не забудьте также назначить ход noexcept.   -  person aschepler    schedule 29.03.2020


Ответы (2)


Не используйте получатель в конструкторе перемещения или присваивании перемещения. Просто используйте член напрямую. Я бы, наверное, сделал это для всех участников, чтобы было видно, что они совпадают.

template <typename T>
Matrix<T>::Matrix(Matrix &&m) noexcept :
    rows_(m.rows_), cols_(m.cols_), size_(m.size_), data_(std::move(m.data_))
{
   // changes needed to m?
}

template <typename T>
Matrix<T>& Matrix<T>::operator=(Matrix &&m) noexcept
{
    rows_ = m.rows_;
    cols_ = m.cols_;
    size_ = m.size_;
    data_ = std::move(m.data_);
    // changes needed to m?
    return *this;
}

Класс всегда имеет доступ к своим собственным членам (независимо от того, через какой объект они получают доступ).

Обязательно подумайте, что должно произойти с m теперь, когда его data_ является нулевым указателем. Следует ли его rows_, cols_ и size_ установить в ноль или это не имеет значения? Обычно перемещенный объект должен оставаться в «допустимом, но неуказанном» состоянии, что бы вы ни решили, это означает для вашего класса. Как минимум, вызов деструктора должен быть допустимым, а назначение его чему-то еще должно работать должным образом; это уже так.

Поскольку геттер здесь не нужен, это отдельный вопрос, должен ли открытый интерфейс включать в себя геттер или он должен иметь более удобный тип возврата, например, просто const T* или T*.

person aschepler    schedule 29.03.2020
comment
Класс всегда имеет доступ к своим собственным членам (независимо от того, через какой объект они получают доступ). Я не знал, что спасибо. Но почему std :: move (m.getData ()) не работает. Я не понимаю. Итак, если я использую функцию получения вне класса. Например. 'std :: unique_ptr ‹double› c = std :: make_unique ‹double› (100); c = std :: move (a.getData ()); ' Как я могу переместить данные на другой умный указатель - person YlmzCmlttn; 29.03.2020
comment
Потому что m.getData() - это const, и вы обычно не можете перейти от выражения const. Вам понадобится геттер, который не является const и имеет тип возврата std::unique_ptr<T>& или std::unique_ptr<T>&&. Тогда это не столько получатель, сколько метод передачи данных. - person aschepler; 29.03.2020

Делает:

 template <typename _T>
    Matrix_<_T>& Matrix_<_T>::operator=(Matrix_&& _m) noexcept {
        rows_ = _m.rows_;
        cols_ = _m.cols_;
        size_ = rows_*cols_;
        data_ = std::move(_m.data_);
        return *this;
    }

Исправлю код. Вам не нужно использовать функцию получения внутри класса, только если вы хотите получить доступ к члену вне класса.

person Waqar    schedule 29.03.2020