Lvalues and rvalues
An expression is an lvalue (left value) if it has a memory address and can be assigned. An rvalue is a temporary value without a stable address.
int x = 5; // x is an lvalue (has an address)
5 // is an rvalue (temporary)
x + 2 // is an rvalue (temporary result)Note
An lvalue can appear on the left side of an assignment; an rvalue cannot:
5 = x;is invalid.
Rvalue references (&&)
A && reference (rvalue reference) binds to temporary values (rvalues). It allows distinguishing whether we are dealing with a temporary object that can be “stolen” or moved:
int&& rref = 5; // rref binds to the temporary 5Move semantics
“Moving” an object transfers its resources (like a std::string’s buffer) instead of copying them. It is cheaper than copying.
std::string a = "Hello very long world";
std::string b = std::move(a); // moves a's content to b, without copying
// a is left in a valid but "empty/unspecified" stateWarning
After
std::move, the source object is left in a valid but unspecified state (usually empty). Don’t use it unless you reassign or destroy it.
std::move
std::move(x) converts x to an rvalue, allowing the move constructor to be used instead of the copy constructor.
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = std::move(v1); // v2 steals v1's bufferMove constructor and move assignment
class Buffer {
int* data;
public:
Buffer(Buffer&& other) noexcept // move constructor
: data(other.data) {
other.data = nullptr; // leave the source without the resource
}
Buffer& operator=(Buffer&& other) noexcept { // move assignment
if (this != &other) {
delete[] data; // free own resource
data = other.data;
other.data = nullptr;
}
return *this;
}
};Note
C++ move is optional and explicit: it only happens if you use
std::moveor if the object is a temporary rvalue.
Rule of Three / Five / Zero
If a class manages resources manually, it must define a coherent set of special methods.
Rule of Three
If you define the destructor, copy constructor, or copy assignment, you usually need all three:
- Destructor
- Copy constructor
- Copy assignment
Rule of Five
With move semantics (C++11), two more are added:
- Move constructor
- Move assignment
Warning
If you define a destructor but not copy or move, the compiler generates default versions that can cause double frees or leaks. Correctly defining only one of the five usually requires defining them all.
Rule of Zero
If the class does not manage resources manually (it uses STL types like std::string or std::vector), define none: let the compiler generate everything by default. It is the simplest and safest.
class Person {
std::string name; // the STL manages its resources
int age;
// No special method is defined: Rule of Zero
};Tip
In general, prefer the Rule of Zero: use smart pointers and STL containers so you don’t have to write destructors or copy constructors by hand.
Next: Templates