Move semantics

C++11 introduced the concept of move semantics, which is kind of an optimized way to copy data. When an object is moved, the contents of the object is taken over by the destination, this is different from copying the data because no valuable data is left in the old object. Move operations are therefore faster because no copying is involved, we simply move the contents of one object into another.

This changed very much how solid objects are handled in C++. Before, returning an object from a function was in many cases too expensive since all the data in the returned object would be copied to the new object. This led to the coding pattern of returning pointers to data, or to pass the return value as a parameter to a function.

However, using move semantics, we can instead return solid objects from functions without any performance penalties

The downside is that we now need to consider implementing the move constructor and move assignment operator when creating a class, in addition to the copy constructor, copy assignment operator and destructor.

Move constructor and Move assignment operator

These operators take the following form

In the move constructor and move assignment operator, you are free to steal whatever data there is in the other object. The double ample sand (&&) means an r-value reference, and this is a reference to an object which is about to die, meaning that it is going to go out of scope and we can take whatever is in it. So for example, if the class in the previous example contained a pointer to a buffer, we could take ownership of this in the move constructor, like this

However this contains a lot of duplicated code, which is very bad. A good way around this is to let the move constructor call the move assignment operator

Which is a lot shorter!

The standard containers are with C++11 also move-enabled, i.e. there are move constructor and move assignment operators defined in each of them. For example when returning a vector from a function, the created vector is moved to the outer scope and the internal pointer is moved from the dying object to the new object.

As a side note, there is sometimes a point in making a class movable by defining the move assignment operator and move constructor but prohibiting copying the class by deleting the copy constructor and copy assignment operator. An example of a class where this is done is the std::unique_ptr, which if it would allow copying would make the pointer not unique which is contrary to the whole point of the class!

Recommendations

  • To prevent memory leaks, always free any resource which may be present in the current object before taking over the other objects data in the move constructor and move assignment operators.
  • Always check for self-assignment in the move assignment operator.
  • Make use of the move assignment operator in the move constructor to remove redundancy.
  • If you define a move constructor, then also add a move assignment operator (see the C++ core guidelines).
Facebookgoogle_pluslinkedinmail

Leave a Reply

Your email address will not be published. Required fields are marked *