rvalue References Wrap Up

The last weeks I have been writing a lot about move semantics, move operations, rvalue references and forwarding references. While it might take a bit of getting used to all this, there’s good news.

You probably won’t need it (much)

Don’t get me wrong. I did not write four posts about some useless stuff. It is all but useless. In fact, it is one of the most important features of C++11, and everyone should know and understand the concepts behind it.

However, it is a feature designed to work under the hood, and unless you write a library or special utility classes or functions (i.e. if you write the stuff that is under the hood), you will seldom need to write the `&&` explicitly in your code.

Let’s recap the places where rvalue references and forwarding references could be written:

Move constructor and move assignment

Don’t write those by hand, unless you absolutely need to. Remember the Rule of All or Nothing? That’s the one telling you that you should not write them (the “nothing” part), unless you write copy constructor, copy assignment and destructor as well.

The only time you need to write them are classes where you have to manage some responsibility manually, and the SRP demands that you write special utility classes for those occasions or use existing ones like `std::unique_ptr`. Your “normal” classes should only be composed of such utility classes, so the compiler takes care of the move operations automatically.

Other object sinks

In most cases, if call by reference is not appropriate and you have a real object sink (e.g. in constructors that take multiple arguments to construct object members from), call by value is the right way to go, so you don’t have to overload for rvalue and lvalue references.

Call-by-rvalue-reference should be an option only in the very rare case that even a move operation causes an unacceptable performance loss.

Perfect forwarding

Perfect forwarding only makes sense in template functions, which in turn means that you will have need for it only in utility functions and libraries that need to be generic. In most garden variety code you will be able to write less generic functions that work without the extra readability burden of `std::forward` without sacrificing performance.

What you do need

The one thing you will need and should use is `std::move`. Know when you have a movable lvalue that you don’t need any more, so when you pass it to a function that is call by value or call by rvalue reference, you `std::move` it explicitly.

Always consider using `std::move` when calling a function with objects that you don’t need after the call.

Other implications

Move operations also mean that assignments of function return values often are not as costly as they used to be. For example, the often used technique of out-parameters for functions that generate and assign an object is often not necessary any more, since simply assigning the return value of the function will move the big object instead of copying it.

Conclusion

Rvalue references and move semantics are a key concept to modern C++, and every C++ developer should know how it works. However, besides explicitly moving objects to take advantage of their movability, this language feature in most cases is best kept under the hood.

Let the compiler do the work of giving you the benefit of move semantics.

Previous Post
Next Post

Leave a Reply

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