This question already has an answer here:
I don't understand when I should use std::move
and when I should let the compiler optimize... for example:
using SerialBuffer = vector< unsigned char >;
// let compiler optimize it
SerialBuffer read( size_t size ) const
{
SerialBuffer buffer( size );
read( begin( buffer ), end( buffer ) );
// Return Value Optimization
return buffer;
}
// explicit move
SerialBuffer read( size_t size ) const
{
SerialBuffer buffer( size );
read( begin( buffer ), end( buffer ) );
return move( buffer );
}
Which should I use?
If you're returning a local variable, don't use
move()
. This will allow the compiler to use NRVO, and failing that, the compiler will still be allowed to perform a move (local variables become R-values within areturn
statement). Usingmove()
in that context would simply inhibit NRVO and force the compiler to use a move (or a copy if move is unavailable). If you're returning something other than a local variable, NRVO isn't an option anyway and you should usemove()
if (and only if) you intend to pilfer the object.All return values are either already
moved
or optimized out, so there is no need to explicitly move with return values.Compilers are allowed to automatically move the return value (to optimize out the copy), and even optimize out the move!
Section 12.8 of n3337 standard draft (C++11):
Use exclusively the first method:
This will already allow the use of the move constructor, if one is available. In fact, a local variable can bind to an rvalue reference in a
return
statement precisely when copy elision is allowed.Your second version actively prohibits copy elision. The first version is universally better.
It's quite simple.
return buffer;
If you do this, then either NRVO will happen or it won't. If it doesn't happen then
buffer
will be moved from.return std::move( buffer );
If you do this, then NVRO will not happen, and
buffer
will be moved from.So there is nothing to gain by using
std::move
here, and much to lose.There is one exception to this rule:
If
buffer
is an rvalue reference, then you should usestd::move
. This is because references are not eligible for NRVO, so withoutstd::move
it would result in a copy from an lvalue.This is just an instance of the rule "always
move
rvalue references andforward
universal references", which takes precedence over the rule "nevermove
a return value".