Move Semantics & Rvalue References
An rvalue reference (T&&) binds to objects that are about to expire, letting a move steal their resources instead of copying — turning an O(n) deep copy into an O(1) pointer swap.
Why it matters
Move semantics (C++11) is why returning a std::vector or passing a std::string by value is cheap: ownership of the heap buffer transfers instead of being duplicated. It is the engine behind std::unique_ptr (a move-only type), efficient container growth, and std::move/std::forward. Without it, every value-returning factory would copy megabytes.
How it works
T& binds lvalues (named, persistent); T&& binds rvalues (temporaries, std::move(x)). A move constructor/assignment takes T&&, pilfers the source’s internals, and leaves the source in a valid but unspecified state.
std::move(x)is just astatic_cast<T&&>— it does not move, it only enables a move overload to be picked.- A
T&¶meter is itself an lvalue (it has a name); pass it on withstd::move/std::forward, or the next call copies. - Forwarding references:
template<class T> f(T&&)deducesT&for lvalues andTfor rvalues; preserve the category withstd::forward<T>.
| You have | Category | Move applies? |
|---|---|---|
make_x() | rvalue (prvalue) | yes |
std::move(named) | rvalue (xvalue) | yes |
named lvalue | lvalue | no (copies) |
T&& parameter | lvalue | no until you std::move it |
Example
std::vector<int> v = make_big(); // returned by value: moved (or elided), no deep copy
std::vector<int> w = std::move(v); // steals v's buffer: O(1); v is now empty-but-valid
std::string s = "...";
sink(std::move(s)); // s usable only after reassignmentA move ctor for a string copies 3 pointers (~24 bytes) regardless of the string’s length; a copy would memcpy the whole payload.
Pitfalls
- Using a moved-from object’s value is a bug; it is valid (you may assign/destroy it) but its contents are unspecified.
std::moveon aconst Tsilently copies — you can’t steal from a const object, so the move overload is rejected.return std::move(local)disables copy elision (NRVO) and is usually slower; justreturn local;.- Forgetting
std::forwardin a forwarding wrapper turns every rvalue into a copy.