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

Variables on the stack

I think one very underused feature in C++ today is simply storing objects on the stack. Many developers who have started writing C# or Java are used to always using new to declare a variable and do the same thing when they are writing C++. And when they later learn that you should never write a naked new, they instead start using unique_ptr or shared_ptr to manage the lifetime of their objects. What they are forgetting is that many times is it sufficient to simply store the instance that you are creating on the stack as a solid object, either as a member of a class or in the local function scope.

The standard library does this all the time, you write

never ever

If you are certain what type of object you need and when you need it, then simply put it on the local stack!

For often called methods you will get a performance increase by doing this since the allocation of an object on the free store takes some time (new has to locate a free portion of memory to allocate).

The exceptions where you don’t want to allocate the object on the local stack include cases where you may want polymorphic behavior, or the class contains large amounts of data making the object too large for the stack.

Facebookgoogle_pluslinkedinmail