rvalues are generally temporary values which are discarded and destroyed immediately after creation (with a few exceptions). std::string&&
is a reference to a std::string
that will only bind to an rvalue. Prior to C++11, temporaries would only bind to std::string const&
-- after C++11, they also bind to std::string&&
.
A variable of type std::string&&
behaves much like a bog-standard reference. It is pretty much only in the binding of function signatures and initialization that std::string&&
differs from std::string&
variables. The other way it differs is when you decltype
the reference. All other uses are unchanged.
On the other hand, if a function returns a std::string&&
, it is very different than returning a std::string&
, because the second kind of thing that can be bound to a std::string&&
is the return value of a function returning std::string&&
.
std::move
is the most common way to generate such a function. In a sense, it lies to the context it is in and tells it "I am a temporary, do with me what you will". So std::move
takes a reference to something, and does a cast that makes it pretend to be a temporary -- aka, rvalue.
Move constructors and move assignment and other move-aware functions take an rvalue reference to know when the data they are passed is "scratch" data that they can "damage" to some extent when using it. This is very useful because many types (from containers, to std::function
, to anything that uses the pImpl
pattern, to non-copyable resources) can have their internal state moved much easier than it can be copied. Such a move changes the state of the source object: but because the function is told it is scratch data, that isn't impolite.
So the move
happens not in std::move
, but in the function that understands that the return value of std::move
implies that it is permitted to modify the data in a somewhat destructive manner if that would help it.
The other ways you can get an rvalue, or an indication that the source object is "scratch data", is when you have a true temporary (an anonymous object created as the return of some other function, or one created using function-style constructor syntax), or when you return from a function with a statement of the form return local_variable;
. In both cases, the data binds to rvalue references.
The short version is that std::move
does not move, and std::forward
does not forward, it just indicates that such an action would be allowed at this point, and lets the function/constructor being called decide what to do with that information.