Each C++ expression (an operator with its operands, 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.
Primary categories
The primary value categories correspond to two properties of expressions:
- has identity: it's possible to determine whether the expression refers to the same entity as another expression, such as by comparing addresses of the objects or functions they identify (obtained directly or indirectly);
- can be moved from: move constructor, move assignment operator, or another function overload that implements move semantics can bind to the expression.
Expressions that:
- have identity and cannot be moved from are called lvalue expressions;
- have identity and can be moved from are called xvalue expressions;
- do not have identity and can be moved from are called prvalue expressions;
- do not have identity and cannot be moved from are not used.
lvalue
An lvalue ("left value") expression is an expression that has identity and cannot be moved from. The naming is historic and reflects the use of lvalue expressions as the left-hand operand of the assignment operator in the CPL programming language.
The following expressions are lvalue expressions:
- 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; - a function call or an overloaded operator expression of lvalue reference return type, such as
std::getline(std::cin, str)
,std::cout << 1
,str1 = str2
or++it
; -
a = b
,a += b
,a %= b
, and all other built-in assignment and compound assignment expressions; -
++a
and--a
, the built-in pre-increment and pre-decrement expressions; -
*p
, the built-in indirection expression; -
a[n]
andp[n]
, the built-in subscript expressions, except wherea
is an array rvalue (since C++11); -
a.m
, the member of object expression, except wherem
is a member enumerator or non-static member function, or wherea
is an rvalue andm
is a non-static data member of non-reference type; -
p->m
, the built-in member of pointer expression, except wherem
is a member enumerator or non-static member function; -
a.*mp
, the pointer to member of object expression, wherea
is an lvalue andmp
is a pointer to data member; -
p->*mp
, the built-in pointer to member of pointer expression, wheremp
is a pointer to data member; -
a, b
, the built-in comma expression, whereb
is an lvalue; -
a ? b : c
, the ternary conditional expression for somea
,b
, andc
; - a string literal, such as
"Hello, world!"
; - a cast expression to lvalue reference type, such as
static_cast<int&>(x)
;
| (since C++11) |
Properties:
- Same as glvalue (below).
- Address of an lvalue may be taken:
&++i
[1] 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.
rvalue (until C++11)prvalue (since C++11)
A prvalue ("pure rvalue") expression is an expression that does not have identity and can be moved from.
The following expressions are prvalue expressions:
- a literal (except for string literal), such as
42
,true
ornullptr
; - a function call or an overloaded operator expression of non-reference return type, such as
str.substr(1, 2)
,str1 + str2
orit++
; -
a++
anda--
, the built-in post-increment and post-decrement expressions; -
a + b
,a % b
,a & b
,a << b
, and all other built-in arithmetic expressions; -
a && b
,a || b
,~a
, the built-in logical expressions; -
a < b
,a == b
,a >= b
, and all other built-in comparison expressions; -
&a
, the built-in address-of expression; -
a.m
, the member of object expression, wherem
is a member enumerator or a non-static member function[2], or wherea
is an rvalue andm
is a non-static data member of non-reference type (until C++11); -
p->m
, the built-in member of pointer expression, wherem
is a member enumerator or non-static member function[2]; -
a.*mp
, the pointer to member of object expression, wheremp
is a pointer to member function[2], or wherea
is an rvalue andmp
is a pointer to data member (until C++11); -
p->*mp
, the built-in pointer to member of pointer expression, wheremp
is a pointer to member function[2]; -
a, b
, the built-in comma expression, whereb
is an rvalue; -
a ? b : c
, the ternary conditional expression for somea
,b
, andc
; - a cast expression to non-reference type, such as
static_cast<double>(x)
,std::string{}
, or(int)42
;
| (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 cv-qualified.
- A prvalue cannot have incomplete type (except for type void, see below, or when used in decltype specifier).
xvalueAn xvalue ("expiring value") expression is an expression that has identity and can be moved from. The following expressions are xvalue expressions:
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) |
Mixed categories
glvalue
A glvalue ("generalized lvalue") expression is an expression that is either an lvalue or an xvalue. It has identity. It may or may not be moved from.
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.
- A glvalue can have incomplete type, where permitted by the expression.
rvalue
An rvalue ("right value") expression is an expression that is either a prvalue or an xvalue. It can be moved from. It may or may not have identity. The naming is historic and reflects the use of rvalue expressions as the right-hand operand of the assignment operator in the CPL programming language.
Properties (note: these apply to 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 can't be used as the left-hand operand of the built-in assignment or compound assignment operator.
- 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) |
Special categories
Pending member function call
The expressions a.mf
and p->mf
, where mf
is a non-static member function, and the expressions a.*mfp
and p->*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 the function call operator, e.g. (p->*mfp)(args)
.
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-hand operand 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 second and third operands).
Bit fields
An expression that designates a bit field (e.g. a.m
, where a
is an lvalue of type struct A { int m: 3; }
) is an lvalue expression: it may be used as the left-hand operand 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.
Footnotes
- Assuming
i
has built-in type or the pre-increment operator is overloaded to return by lvalue reference - special rvalue category, see pending member function call
- Assuming
i
has built-in type or the postincrement operator is not overloaded to return by lvalue reference
External references
"New" Value Terminology by Bjarne Stroustrup, 2010.
Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 616 | C++11 | member access and member access through pointer to member of an rvalue resulted in prvalue | reclassified as xvalue |
CWG 1213 | C++11 | subscripting an array rvalue resulted in lvalue | reclassified as xvalue |
See also
C documentation for value categories |
Please login to continue.