Move Semantics and Rvalue References
C++11 introduced move semantics — a way to transfer ownership of resources instead of copying them. This is one of the biggest performance improvements in modern C++.
Lvalues vs Rvalues
An lvalue is an expression that identifies an object (you can take its address):
int x = 42; // x is an lvalue
int& ref = x; // ref is an lvalue reference (can't bind to rvalue)An rvalue is a temporary value (you can't take its address):
int y = x + 1; // (x + 1) is an rvalue, 42 is an rvalue
int&& rref = 42; // rref is an rvalue referencestd::move
std::move doesn't actually move anything — it casts an lvalue to an rvalue, enabling the move constructor:
std::vector<int> v1 = {1, 2, 3, 4, 5};
std::vector<int> v2 = std::move(v1);
// v1 is now empty — its internal buffer was moved to v2
// No elements were copied; just a pointer assignmentMove Constructor and Move Assignment
class MyString {
char* data;
size_t len;
public:
// Move constructor
MyString(MyString&& other) noexcept
: data(other.data), len(other.len) {
other.data = nullptr; // take ownership
other.len = 0;
}
// Move assignment
MyString& operator=(MyString&& other) noexcept {
if (this != &other) {
delete[] data; // free my old data
data = other.data; // take ownership
len = other.len;
other.data = nullptr;
other.len = 0;
}
return *this;
}
};When Move Is Called
std::vector<int> makeVector() {
std::vector<int> v = {1, 2, 3};
return v; // move (or copy elision in C++17+)
}
std::vector<int> v = makeVector(); // move constructor called
v.push_back(4); // might reallocate and move existing elementsMove semantics eliminates expensive deep copies by transferring ownership of underlying resources (heap memory, file descriptors, etc.).
Perfect Forwarding
std::forward preserves the value category (lvalue/rvalue) when passing arguments through generic wrapper functions. This is used in std::make_unique, std::make_shared, and std::thread.