Value categories
Each C++ expression (an operator with its arguments, a literal, a variable name, etc) is characterized by two independent properties: a type and a value category. Each expression has some non-reference type, and each expression belongs to exactly one of the three primary value categories.
Contents |
[edit] Primary categories
[edit] lvalue
An lvalue is an expression that identifies a non-temporary object or a non-member function.
The following expressions are lvalues:
- The name of an object or function in scope, regardless of type, such as
std::cin
orstd::endl
. Even if the object's type is rvalue reference, the expression consisting of its name is an lvalue expression. - Function call or operator expression if the function's or operator's return type is an lvalue reference, such as
std::getline(cin, str)
orstd::cout << 1
ora = b
or++n
or*p
[1] - Cast expression to lvalue reference type.
- String literal
|
(since C++11) |
Properties:
- Same as glvalue (below)
- Address of an lvalue may be taken:
&++i
[2] and&std::endl
are valid expressions. - A modifiable lvalue may be used as the first (left) argument of the built-in assignment operator.
- An lvalue may be used to initialize an lvalue reference; this associates a new name with the object identified by the expression.
[edit] rvalue (until C++11) / prvalue (since C++11)
A prvalue ("pure" rvalue) is an expression that identifies a temporary object (or a subobject thereof) or is a value not associated with any object.
The following expressions are prvalues:
- Literal (except string literal), such as 42 or true or nullptr.
- Function call/operator expression if the function's or the operator's return type is not a reference, such as
str.substr(1, 2)
or2+2
- Cast expression to any type other than reference type.
|
(since C++11) |
Properties:
- Same as rvalue (below)
- a prvalue cannot be polymorphic: the dynamic type of the object it identifies is always the type of the expression.
- a non-class prvalue cannot be const-qualified.
xvalueAn xvalue is an expression that identifies an "eXpiring" object, that is, the object that may be moved from. The object identified by an xvalue expression may be a nameless temporary, it may be a named object in scope, or any other kind of object, but if used as a function argument, xvalue will always bind to the rvalue reference overload if available. Only the following expressions are xvalues:
Properties:
Like prvalues, xvalues bind to rvalue references, but unlike prvalues, an xvalue may be polymorphic, and a non-class xvalue may be cv-qualified. |
(since C++11) |
[edit] Mixed categories
[edit] glvalue
A glvalue ("generalized" lvalue) is an expression that is either an lvalue or an xvalue.
Properties (note: these apply to pre-C++11 lvalues as well)
- A glvalue may be implicitly converted to prvalue with lvalue-to-rvalue, array-to-pointer, or function-to-pointer implicit conversion.
- A glvalue may be polymorphic: the dynamic type of the object it identifies is not necessarily the static type of the expression.
[edit] rvalue
An rvalue is an expression that is either a prvalue or an xvalue.
Properties (note, these apply to both xvalues and prvalues, which means they apply to the pre-C++11 rvalues as well)
- Address of an rvalue may not be taken:
&int()
,&i++
[3],&42
, and&std::move(val)
are invalid. - An rvalue may be used to initialize a const lvalue reference, in which case the lifetime of the object identified by the rvalue is extended until the scope of the reference ends.
|
(since C++11) |
[edit] Special categories
[edit] Pending member function call
The expressions obj.func and ptr->func, where func
is a non-static member function, and the expressions obj.*mfp and ptr->*mfp where mfp
is a pointer to member function, are classified as prvalue expressions, but they cannot be used to initialize references, as function arguments, or for any purpose at all, except as the left-hand argument of a function call expression, e.g. (pobj->*ptr)(args).
[edit] Void expressions
Function call expressions returning void, cast expressions to void, and throw-expressions are classified as prvalue expressions, but they cannot be used to initialize references or as function arguments. They can be used in a discarded-value context (e.g. on a line of its own, as the left argument of the comma operator, etc) and in the return statement in a function returning void. In addition, throw-expressions (but not other void prvalues) may be used as the second and the third operands of the conditional operator ?:.
[edit] Bit fields
An expression that designates a bit field (e.g. s.x
where s is an object of type struct S { int x:3; };
) is an lvalue expression: it may be used on the left hand side of the assignment operator, but its address cannot be taken and a non-const lvalue reference cannot be bound to it. A const lvalue reference can be initialized from a bit-field lvalue, but a temporary copy of the bit-field will be made: it won't bind to the bit field directly.
[edit] footnotes
-
↑ assuming
a
,b
,n
,p
have built-in types or the assignment, pre-increment, and dereference operators aren't overloaded to return by value -
↑ Assuming
i
has built-in type or the pre-increment operator is not overloaded to return by value -
↑ Assuming
i
has built-in type or the postincrement operator is not overloaded to return by reference