【问题标题】:How I can implement move constructor and operator for unique_ptr as a private member of class如何将 unique_ptr 的移动构造函数和运算符实现为类的私有成员
【发布时间】:2020-07-09 22:59:34
【问题描述】:

我正在尝试编写 Matrix 类。我使用 unique_ptr 作为存储指针数组。但是这个 unique_ptr 是 private 类的成员。我想将移动构造函数添加到我的 Matrix 类。但是我需要 getter 函数用于私有 unique_ptr 但是当我将 unique_ptr 作为 const 变量返回时,我不能使用 std::move 但是当我返回没有 const 参考编译器的 getter 函数时'不允许这样。

矩阵.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;

【问题讨论】:

  • 为什么你需要一个 getter 来表示内部数据,并且 在 getter 调用之后应该是这个数据的所有者?它是否仍应归 Matrix_ 所有,还是应让 getter 调用者成为数据的唯一所有者?
  • 所有者必须相同 我需要 getter 来获取参数的数据成员,例如 'Matrix_<_t>::Matrix_(Matrix_&& m)' 我需要获取 _m 的数据变量
  • 这是一个member函数。成员函数可以访问类的所有私有成员(无论要访问同一个对象还是不同对象,类都是一样的)。如果您需要从类的 outside 访问它(也就是不是 Matrix_ 成员的任何函数),您只需要一个 getter
  • 谢谢。我不知道。但我仍然想知道为什么我不能使用 getData() 我返回私有成员作为参考
  • 不要使用以下划线开头后跟大写字母的标识符;这些是为实现而保留的。不要忘记同时进行移动分配noexcept

标签: c++ smart-pointers move-semantics move-constructor


【解决方案1】:

不要在移动构造函数或移动赋值中使用 getter。直接使用会员即可。我可能会为所有成员这样做,以使其明显匹配。

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;
}

一个类总是可以访问它自己的成员(无论它们是通过哪个对象访问的)。

既然data_ 是一个空指针,请务必考虑m 会发生什么。应该将其rows_cols_size_ 设置为零,还是没有关系?通常,移出对象应处于“有效但未指定”状态,无论您决定这对您的班级意味着什么。至少,调用析构函数应该是有效的,并且将它分配给其他东西应该可以按预期工作;已经是这样了。

由于这里不需要 getter,公共接口是否应该包含一个 getter,或者它是否应该具有更方便的返回类型,例如 const T*T*,这是一个单独的问题。

【讨论】:

  • "一个类总是可以访问它自己的成员(无论它们是通过哪个对象访问的)。"我不知道谢谢。但是为什么 std::move(m.getData()) 不起作用。我不明白。因此,如果我在课外使用 getter 函数。例如。 'std::unique_ptr c = std::make_unique(100); c = std::move(a.getData());'如何将数据移动到另一个智能指针
  • 因为m.getData()const,并且您通常不能从const 表达式中移动。您需要一个不是const 并且返回类型为std::unique_ptr&lt;T&gt;&amp;std::unique_ptr&lt;T&gt;&amp;&amp; 的getter。那么这与其说是一种吸气剂,不如说是一种提供数据的方法。
【解决方案2】:

在做:

 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;
    }

将修复代码。类内不需要使用getter函数,只需要在类外访问成员时使用即可。

【讨论】:

    猜你喜欢
    • 2013-03-27
    • 2020-04-06
    • 1970-01-01
    • 2019-05-17
    • 1970-01-01
    • 2017-05-15
    • 1970-01-01
    • 1970-01-01
    • 2013-05-04
    相关资源
    最近更新 更多