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: prvalue, xvalue, lvalue, defined as follows:
Note: this taxonomy went through significant changes with past C++ standard revisions, see History below for details.
The following expressions are lvalue expressions:
std::cin
or std::endl
. Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression; 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]
and p[n]
, the built-in subscript expressions, except where a
is an array rvalue (since C++11); a.m
, the member of object expression, except where m
is a member enumerator or a non-static member function, or where a
is an rvalue and m
is a non-static data member of non-reference type; p->m
, the built-in member of pointer expression, except where m
is a member enumerator or a non-static member function; a.*mp
, the pointer to member of object expression, where a
is an lvalue and mp
is a pointer to data member; p->*mp
, the built-in pointer to member of pointer expression, where mp
is a pointer to data member; a, b
, the built-in comma expression, where b
is an lvalue; a ? b : c
, the ternary conditional expression for some a
, b
, and c
; "Hello, world!"
; static_cast<int&>(x)
;
| (since C++11) |
Properties:
&++i
^{[1]} and &std::endl
are valid expressions. The following expressions are prvalue expressions:
42
, true
or nullptr
; str.substr(1, 2)
, str1 + str2
, or it++
; a++
and a--
, 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, where m
is a member enumerator or a non-static member function^{[2]}, or where a
is an rvalue and m
is a non-static data member of non-reference type (until C++11); p->m
, the built-in member of pointer expression, where m
is a member enumerator or a non-static member function^{[2]}; a.*mp
, the pointer to member of object expression, where mp
is a pointer to member function^{[2]}, or where a
is an rvalue and mp
is a pointer to data member (until C++11); p->*mp
, the built-in pointer to member of pointer expression, where mp
is a pointer to member function^{[2]}; a, b
, the built-in comma expression, where b
is an rvalue; a ? b : c
, the ternary conditional expression for some a
, b
, and c
; static_cast<double>(x)
, std::string{}
, or (int)42
; this
pointer;
| (since C++11) |
Properties:
The following expressions are xvalue expressions:
std::move(x)
; a[n]
, the built-in subscript expression, where one operand is an array rvalue ; a.m
, the member of object expression, where a
is an rvalue and m
is a non-static data member of non-reference type; a.*mp
, the pointer to member of object expression, where a
is an rvalue and mp
is a pointer to data member; a ? b : c
, the ternary conditional expression for some a
, b
, and c
; static_cast<char&&>(x)
.
| (since C++17) |
Properties:
In particular, like all rvalues, xvalues bind to rvalue references, and like all glvalues, xvalues may be polymorphic, and non-class xvalues may be cv-qualified.
A glvalue expression is either lvalue or xvalue.
Properties:
An rvalue expression is either prvalue or xvalue.
Properties:
&int()
, &i++
^{[3]}, &42
, and &std::move(x)
are invalid.
| (since C++11) |
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)
.
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 discarded-value 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 ?:.
Void expressions have no result object. | (since C++17) |
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.
The programming language CPL was first to introduce value categories for expressions: all CPL expressions can be evaluated in "right-hand mode", but only certain kinds of expression are meaningful in "left-hand mode". When evaluated in right-hand mode, an expression is regarded as being a rule for the computation of a value (the right-hand value, or rvalue). When evaluated in left-hand mode an expression effectively gives an address (the left-hand value, or lvalue). "Left" and "Right" here stood for "left of assignment" and "right of assignment".
The C programming language followed a similar taxonomy, except that the role of assignment was no longer significant: C expressions are categorized between "lvalue expressions" and others (functions and non-object values), where "lvalue" means an expression that identifies an object, a "locator value"^{[4]}
Pre-2011 C++ followed the C model, but restored the name "rvalue" to non-lvalue expressions, made functions into lvalues, and added the rule that references can bind to lvalues, but only references to const can bind to rvalues. Several non-lvalue C expressions became lvalue expressions in C++.
With the introduction of move semantics in C++11, value categories were redefined to characterize two independent properties of expressions^{[5]}:
In C++11, expressions that:
The expressions that have identity are called "glvalue expressions" (glvalue stands for "generalized lvalue"). Both lvalues and xvalues are glvalue expressions.
The expressions that can be moved from are called "rvalue expressions". Both prvalues and xvalues are rvalue expressions.
In C++17, copy elision was made mandatory in some situations, and that required separation of prvalue expressions from the temporary objects initialized by them, resulting in the system we have today.
i
has built-in type or the pre-increment operator is overloaded to return by lvalue reference i
has built-in type or the postincrement operator is not overloaded to return by lvalue reference 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 |
C documentation for value categories |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
http://en.cppreference.com/w/cpp/language/value_category