Reputation: 6425
I like the new std::move
but afraid that it reduces my program maintainability.
To my knowledge, if I create move constructor
or move assignment operator=()
, I have to write it from scratch. That is where the problem begins.
Here is a tiny 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;
Currently, B b2=b1
will copy both M
and C
. It is ok.
Now I want to use the power of 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);
It is still ok, but a bit tedious. (1#)
Then one month in the future, I may want to add a new field e.g. C shouldBeCopy2
to B
, I also have to add a line into operator=
:-
B& operator=(B&& that){
this->shouldBeMove=std::move(that.shouldBeMove);
this->shouldBeCopy=that.shouldBeCopy;
this->shouldBeCopy2=that.shouldBeCopy2; //<--- new line
}
I think I am a type that may forget to add that line. (2#)
1#. How to make it not tedious?
2#. How to foolproof my mistake?
Upvotes: 2
Views: 87
Reputation: 46578
You should follow rule of zero and let compiler generate the constructors and assign operators for you.
But when you need to implement a moveable type, make sure you implement both move assignment operator (T& operator=(T&&)
) and move constructor (T(T&&)
). Please follow rule of five and ensure the class have proper copy constructor/move constructor/copy assignment operator/move assignment operator/destructor
#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;
}
Upvotes: 1