On Dangers of C++ Move Semantics
Doing some programming with extensive use of move semantics I had several major bugs in my handling of object state in move constructors/assignment operators and destructors. But it wasn't because of my lack of heed or skill. It was the direct result of having to keep synchronized three places in the code: move constructor/assignment operator and destructor.
So consider this:
struct test {
...constructors...
test( test&& other ) : data{ other.data } { //better to always std::move
other.data = nullptr; //<------
}
test& operator==( test&& other ) { //may be unnecessary if using copy-and-swap idiom
data = other.data; //for simplicity
other.data = nullptr; //<------
return *this;
}
~test() {
if( data ) { //<------
...
}
}
void *data;
};
Three places! Well, okay, minimum two places that you have to keep track of and keep in sync. C++ is flexible, so you can partially solve this problem by introducing a wrapper around types. After all you only need special handling in destructors for resources (memory, handles, etc.).
After thinking about it, it seems that the introduction of the move constructor/assignment operator was a bad idea. All we needed is r-value references for the sake of argument deduction, r-values should've been movable by default (and you can't forbid it). If an object is moved then don't call the destructor of such an object - it's empty, no need for move constructors/operators. C++ would've been so much simpler!
UPD: In short we need r-value refs, a bind to an r-value ref always is a move (only that action has meaning with r-values) and because of that no need to call destructors of such (bound to an r-value ref) moved from/empty objects, as a result the user would only rarely need to implement custom move constructors/move assignment operators (maybe some advanced logic) and more often just =default or =delete it.
Another thing to be aware of:
Base test( Base&& object ) { // should we allow binding of an r-value of derived to base?
return std::move( object ); // worse than slicing
}
No warnings in Clang 3.8.0 or GCC 5.3.0: Godbolt