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

C++ std::move assignment from scratch - low maintainability

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

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

代码版本 1

这是一个小 class:-

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#。如何防止我的错误?

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

但是当您需要实现可移动类型时,请确保同时实现移动赋值运算符 (T& operator=(T&&)) 和移动构造函数 (T(T&&))。请遵循五法则并确保 class 具有正确的副本 constructor/move constructor/copy 赋值 operator/move 赋值 operator/destructor

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