Move It

Since C++11, move construction and assignment have ushered in a golden age of efficiency. When you want to transfer ownership of an object, you have neither to copy and delete the object nor dynamically allocate it. (So long as the object supports moving.)

Until C++17, adding std::move calls where they weren’t needed would do no worse than clutter up the code. Since C++17 specifies when return-value optimization must be performed, unnecessary moves can now make your code less efficient.

You Must Not Move

Return Value Optimization is mandated when a function returns a local value whose type matches the function’s return type. std::move, since it yields an rvalue reference, prevents this.

This code is bad and wrong and must not be allowed.

Without the std::move, the return value of the function would have been constructed directly into the location on caller’s stack identified as b. With it, m is default constructed, then b is move-constructed from m. Move construction is cheap, but not free.

If, as above, f returns by value, you must also avoid this.

If f returns by reference, return value optimization never comes into play. It’s perfectly legitimate to move-construct from a non-const lvalue reference.

To guard yourself against these errors, you should always compile with `-Wpessimizing-move1.

You Should Move

For functions returning local values whose type is merely convertible to the return type and for which the return type has a move constructor, we should use std::move.

Wibbly-Wobbly

Function parameters (rather than local variables) do not participate in return value optimization whatever their type is. You will experience no loss of efficiency from returning them. However, when a parameter is returned, its constructor is determined via overload resolution as if it were an rvalue reference. This behavior was made canonical in an amendment to the standard, so some C++17 compilers may not do this. Newer ones do and so this use of std::move is harmless but redundant on new compilers.