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 a variable or function in scope, regardless of type, such as
std::cin
orstd::endl
. Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression. - Function call or overloaded operator expression if the function's or overloaded operator's return type is an lvalue reference, such as
std::getline(std::cin, str)
orstd::cout << 1
orstr1 = str2
or++iter
[1] - Built-in pre-increment and pre-decrement, dereference, assignment and compound assignment, subscript (except on an array xvalue), member access (except for non-static non-reference members of xvalues, member enumerators, and non-static member functions), member access through pointer to data member if the left-hand operand is lvalue, comma operator if the right-hand operand is lvalue, ternary conditional if the second and third operands are lvalues.
- 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 left-hand operand 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.
- An lvalue can have incomplete type, where permitted 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 or overloaded operator expression if the function's or the overloaded operator's return type is not a reference, such as
str.substr(1, 2)
orstr1 + str2
- Built-in post-increment and post-decrement , arithmetic and logical operators, comparison operators, address-of operator, member access for a member enumerator, a non-static member function, or a non-static non-reference data member of an rvalue, member access through pointer to a data member of rvalue or to a non-static member function, comma operator where the right-hand operand is rvalue, ternary conditional where either second or third operands aren't lvalues.
- 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 non-array prvalue cannot be const-qualified.
- a prvalue cannot have incomplete type (except for type void, see below)
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 some contexts (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 may be used as the second and the third operands of the conditional operator ?: (other void prvalues can only be used if appearing as both 2nd and 3rd operands).
[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 (or xvalue if s
is one): 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 the 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