Move semantics is a new concept introduced in C++11 for the case when an object is assigned to another object and is no longer used by itself. Instead of calling the copy constructor of the new object and then destroying the original object, with move semantics, the resources of the original object are “moved” to the new object, e.g.
std::vector assigns a pointer to an array to the new object, instead of requesting a new piece of memory and copying the contents of the original address This avoids costly copy operations. This semantics is especially critical when assigning temporary objects (right values).
In traditional C++ references can only be bound to left values, but in the mobile semantics it is necessary to distinguish between left-valued references, so
&& was introduced in C++11 to represent a reference to a right value and to extend the life of the object.
Although it is said that there is a right-value reference, a question arises, how to call the right-value version of the function? A right-value is a dying object with no name, and for
int&& rx = 12
12 is the right-value, while
rx is just a reference to
12, which itself is still a left-value. So the standard library provides the facility
std::move() to implement the transition.
std::move() it is possible to unconditionally transform left-valued arguments into right-valued references, but this function itself does not move the object, but only transforms it. Here is a possible implementation.
You can see that it’s just a type change, and there are no operations related to the move, not even any runtime performance loss, it’s the function that is really responsible for the move. Applying
std::move() is just to get the compiler to reload correctly to the moved version.
As mentioned before the right value has no name, so in the following case
I want the external function
func_wrapper to be able to do something like write a log before calling the actual function. But the problem is that the function template accepts both left-valued and right-valued references, so how do I determine the argument type when making the call? If the call is made directly, then both are left-valued (even if right-valued is passed, the argument is derived as a right-valued reference and the right-valued reference is considered left-valued), and if all use
std::move then the passed left-valued is also moved. Writing a version for both kinds of references is not good for maintenance, but it is also not possible if the function itself accepts an arbitrary number of arguments.
This leads to
std::forward perfect forwarding for conditional transformation, where passing in a left value forwards to a left value, and passing in a right value forwards to a right value.
Template type derivation collapses all right-valued references to left-valued references except for right-valued to right-valued references. This is the key to implementing
It is worth noting that the type
T must be given explicitly when using forwarding, as this information helps to identify the reference type.
Take the following function as an example
When a left-valued reference is passed in, it is replaced with
void f1(int&& ¶m), where
int&, at which point
std::forward is replaced with
Thus, the left-valued reference is forwarded. When a right-valued reference is passed in the replacement is
void f1(int&& param), where
std::forward is replaced with
The right-valued reference is forwarded, thus enabling a conditional transformation based on the arguments given by the caller to achieve a perfect forwarding of the arguments.
Move semantics is a newly introduced concept.
std::move implements an unconditional transition to the right value, and
std::forward implements a conditional transition to the right value only for right-valued references, both of which have no additional runtime consumption.
std::move is used for right-valued references, and
std::forward is used for generic references.