Considering the high quality of today's compilers regarding return value optimization (both RVO and NRVO), I was wondering at what class complexity it's actually meaningful to start adding move constructors and move assignment operators.
For instance, for this really_trivial
class, I just assume that move semantics cannot offer anything more than RVO and NRVO already does when copying around instances of it:
class really_trivial
{
int first_;
int second_;
public:
really_trivial();
...
};
While in this semi_complex
class, I'd add a move constructor and move assignment operator without hesitation:
class semi_complex
{
std::vector<std::string> strings_;
public:
semi_complex(semi_complex&& other);
semi_complex& operator=(semi_complex&& other);
...
};
So, at what amount and of what kinds of member variables does it start making sense to add move constructors and move assignment operators?
The move assignment operator is different than a move constructor because a move assignment operator is called on an existing object, while a move constructor is called on an object created by the operation. Thereafter, the other object's data is no longer valid.
The move constructor and move assignment operator are simple. Instead of deep copying the source object (a) into the implicit object, we simply move (steal) the source object's resources. This involves shallow copying the source pointer into the implicit object, then setting the source pointer to null.
The Copy constructor and the assignment operators are used to initializing one object to another object. The main difference between them is that the copy constructor creates a separate memory block for the new object. But the assignment operator does not make new memory space.
A move constructor enables the resources owned by an rvalue object to be moved into an lvalue without copying.
It is already meaningful for purely semantic reasons, even if you keep the optimization-aspects out completely. Just imagine the case where a class does not/cannot implement copying. For example boost::scoped_ptr
cannot be copied, but it can be moved!
In addition to the excellent answers already given, I would like to add a few forward-looking details:
There are new rules in the latest C++0x draft for automatically generating a move constructor and move assignment operator. Although this idea is not entirely new, the latest rules have only been in the draft since Oct. 2010, and not yet widely available in compilers.
If your class does not have a user-declared copy constructor, copy assignment operator, move constructor, move assignment operator and destructor, the compiler will provide defaulted move constructor and move assignment operator for you. These default implementations will simply member-wise move everything.
You can also explicitly default your move members:
semi_complex(semi_complex&&) = default;
semi_complex& operator=(semi_complex&&) = default;
Note that if you do so, you will implicitly inhibit copy semantics unless you explicitly supply or default the copy constructor and copy assignment operator.
In a closely related late-breaking change: If your class has an explicit destructor, and implicit copy members, the implicit generation of those members is now deprecated (the committee would like to remove the implicit generation of copy when there is an explicit destructor, but can't because of backwards compatibility).
So in summary, any time you have a destructor declared, you should probably be thinking about explicitly declaring both copy and move members.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With