Value Categories
“All categories have value.”
Basics
| glvalue (identity) |
(identityless) |
|
|---|---|---|
| rvalue (movable) |
xvalue |
prvalue |
| (immovable) | lvalue |
- glvalue: (generalised lvalue) values with an identity, encapsulating
lvaluesandxvalues. - rvalue: (read/right value) values that can be moved, encapsulating
xvaluesandprvalues. - lvalue: (locator/left value) values that cannot be moved (only copied).
- xvalue: (eXpiring value) the result of applying
std::moveto anlvalue. - prvalue: (pure rvalue) values without an identity.
Here I have provided a list of most instances of each value category:
// lvalues
int i; // Named variables are lvalues
"Hello World!"; // String literals have lvalue type 'const char(&)[N]'
*this; // The dereferenced 'this' pointer is an lvalue
void fn() {} // 'fn' is an lvalue
struct { static void fn() {} }; // Static member functions are lvalues
// xvalues
std::move( i );
// prvalues
42; true; nullptr; // Literals are prvalues (except for string literals)
enum { val }; // Enum values are prvalues
i++; // Post-increment/decrement expressions are prvalues
&i; // A variable's address is a prvalue
int{}; // Temporary materialisation results in a prvalue
this; // The 'this' pointer is a prvalue
struct { void fn() {} }; // Non-static member functions are prvalues
// Arithmetic, logical, and comparison expressions also result in prvalues
// Note that the above refers to built-in operations, not user-defined overloads
Conversions always result in a prvalue, demonstrated with the following code snippet:
void fn( int&& ) {}
void fn( float&& ) {}
int main()
{
int i{};
// 'i' cannot find an appropriate 'fn' overload taking an lvalue 'int'
// 'i' can be implicitly converted to 'float&&'
// Thus, 'fn( float&& )` is invoked
fn( i );
}
Values have an identity if they have an accessible address.
This includes variables, the dereferencedthispointer, string literals, etc.
Values without identity (prvalues) include literals, thethispointer, temporary objects (often as the result of an expression), etc.
Such values seize to exist if they are not defined.
Moving a variable refers to reusing its resources to construct/assign another object.
For example, ownership of data pointers is transferred, instead of making a copy of the data.
Continue reading about move semantics here.