Good links are appreciated.
While std::move()
is technically a function - I would say it isn't really a function. It's sort of a converter between ways the compiler considers an expression's value.
The first thing to note is that std::move()
doesn't actually move anything. It changes an expression from being an lvalue (such as a named variable) to being an xvalue. An xvalue tells the compiler:
You can plunder me, move anything I'm holding and use it elsewhere (since I'm going to be destroyed soon anyway)".
in other words, when you use std::move(x)
, you're allowing the compiler to cannibalize x
. Thus if x
has, say, its own buffer in memory - after std::move()
ing the compiler can have another object own it instead.
You can also move from a prvalue (such as a temporary you're passing around), but this is rarely useful.
Another way to ask this question is "What would I cannibalize an existing object's resources for?" well, if you're writing application code, you would probably not be messing around a lot with temporary objects created by the compiler. So mainly you would do this in places like constructors, operator methods, standard-library-algorithm-like functions etc. where objects get created and destroyed automagically a lot. Of course, that's just a rule of thumb.
A typical use is 'moving' resources from one object to another instead of copying. @Guillaume links to this page which has a straightforward short example: swapping two objects with less copying.
template <class T>
swap(T& a, T& b) {
T tmp(a); // we now have two copies of a
a = b; // we now have two copies of b (+ discarded a copy of a)
b = tmp; // we now have two copies of tmp (+ discarded a copy of b)
}
using move allows you to swap the resources instead of copying them around:
template <class T>
swap(T& a, T& b) {
T tmp(std::move(a));
a = std::move(b);
b = std::move(tmp);
}
Think of what happens when T
is, say, vector<int>
of size n. In the first version you read and write 3*n elements, in the second version you basically read and write just the 3 pointers to the vectors' buffers, plus the 3 buffers' sizes. Of course, class T
needs to know how to do the moving; your class should have a move-assignment operator and a move-constructor for class T
for this to work.
std::move
itself does nothing rather than a static_cast
. According to cppreference.com
It is exactly equivalent to a static_cast to an rvalue reference type.
Thus, it depends on the type of the variable you assign to after the move
, if the type has constructors
or assign operators
that takes a rvalue parameter, it may or may not steal the content of the original variable, so, it may leave the original variable to be in an unspecified state
:
Unless otherwise specified, all standard library objects that have been moved from being placed in a valid but unspecified state.
Because there is no special move constructor
or move assign operator
for built-in literal types such as integers and raw pointers, so, it will be just a simple copy for these types.