C ++ std ::从头开始移动分配 - 低可维护性

时间:2016-11-17 04:32:55

标签: c++11 move-semantics maintainability

我喜欢新的std::move,但担心它会降低程序的可维护性。

据我所知,如果我创建move constructormove assignment operator=(),我必须从头开始编写 。这就是问题的开始。

代码版本1

这是一个很小的课程: -

class B{
    M shouldBeMove;  //if it is copied, it is still correct (but prefer move)
    C shouldBeCopy;  //can be copied or moved, both are equal and ok
    //wow, I don't even have to write this line for operator=():-
    //    this->shouldBeCopy = that.shouldBeCopy
}

B b1;
B b2=b1;

目前,B b2=b1将同时复制MC。没关系。

代码版本2

现在我想使用std::move的力量: -

class B{
    M shouldBeMove;  //now, the program is refactored that it must be moved 
    // M now has "M& operator=(M&& that)"
    C shouldBeCopy;
    B& operator=(B&& that){
        this->shouldBeMove=std::move(that.shouldBeMove);
        this->shouldBeCopy=that.shouldBeCopy;   //<-- a bit tedious (1#)
        //  ... imagine that there are 10 variables to be copied ... 
    }
}

B b1;
B b2=std::move(b1);

它仍然可以,但有点乏味。 (1#)

代码版本3

然后将来一个月,我可能想要添加一个新字段,例如C shouldBeCopy2B,我还需要在operator=中添加一行: -

B& operator=(B&& that){
    this->shouldBeMove=std::move(that.shouldBeMove);
    this->shouldBeCopy=that.shouldBeCopy;
    this->shouldBeCopy2=that.shouldBeCopy2;  //<--- new line
}

我认为我是一个可能忘记添加该行的类型。 (2#)

问题:

1#。如何使它不繁琐?
2#。如何万无一失?

1 个答案:

答案 0 :(得分:1)

您应该遵循rule of zero并让编译器生成构造函数并为您分配运算符。

但是当您需要实现可移动类型时,请确保同时实现移动赋值运算符(T& operator=(T&&))和移动构造函数(T(T&&))。请遵循五条规则并确保该类具有适当的复制构造函数/移动构造函数/复制赋值运算符/移动赋值运算符/析构函数

https://ideone.com/UVZNOM

#include <iostream>
using namespace std;

class M{
    public: int database=0;
    M& operator=(M&& other){
        this->database=other.database;
        other.database=0;
        return *this;

    }
    M(M &&other) {
        *this = std::move(other);
    }
    M (M& m)=default;
    M ()=default;
    ~M() { /* free db */ }
};
class B{ // As rule of zero, you don't need to implement constructors and assignment operators 
    public: M shouldMove;
};

int main() {
    B b;
    b.shouldMove.database=5;
    B b2=std::move(b);
    std::cout<< b.shouldMove.database <<std::endl;
    std::cout<< b2.shouldMove.database <<std::endl;
    return 0;
}