Loading lessons...
Move Semantics and std::move
Move Semantics and std::move
Copying data is wasteful when you only want to transfer it. Move semantics lets you transfer resources without copying everything.
Lvalue vs rvalue
- An lvalue is an object you can take an address of:
int a = 5;, a is an lvalue. - An rvalue is a temporary that is about to die: the result of a function call like
foo()or the literal5.
Rvalue references
An rvalue reference is written with &&. It binds only to rvalues:
void set(std::string&& src); // only accepts rvalues
That lets you distinguish "give me a temporary to steal" from "give me one you still need."
Move constructor and move assignment
A move constructor accepts an rvalue reference and steals the other object's resources, leaving it empty:
class Buffer {
int* data;
public:
Buffer(Buffer&& other) : data(other.data) {
other.data = nullptr; // steal and clear the source
}
};
The source ends up empty but valid. This is O(1); copying the large array would be O(N).
std::move
std::move casts an lvalue into an rvalue reference so the move path is chosen from now on:
std::string a = "hello";
std::string b = std::move(a); // b steals a's data
b now owns the string; a is left in a valid but unspecified state.
When it happens automatically
The compiler picks the move constructor whenever you return a local, pass a temporary, or construct from one. For special classes with heavy data, moves make everything fast without you writing a line. A vector's growth also reuses moves, so push_back of a temporary moves.
TL;DR
- rvalue references
&&bind only to temporaries. - A move constructor steals resources cheaply from the source.
std::moveforces the move for an lvalue.- Moving is much cheaper than copying a big buffer.
- First-class situations (returning temporaries) are chosen automatically.