Quick summary ⏠C++ had value categories in C++0X version. The two value categories that were before C++11 are lvalues and rvalues. One of the greatest addition to C++11 was the introduction of movable types. Learning about the value categories is one of the pre-requisites to learn about move semantics. Any expression before the C++11 standard was either lvalue or rvalue. lvalue has an identity and its lifetime depends on the scope of the variable. On the other hand, rvalues don’t have an identity and it does not live beyond the life of the expression.
1. Introduction
Letâs consider few examples to understand l-value and the r-values in depth:
|
|
As already said, before C++11, expressions are categorized as lvalues or rvalues. They are categorized based on the identity of the expression. But, it all changed after the C++11 standard version. Expressions are now categorized based on identity and movability. Below is the short definition for all the value categories.
x-values -> âItâs abbreviated as âExpiring valuesâ. Refers to objects that nears the end of itâs lifetime. Example: Result of calling a function that returns r-value reference is an x-value. It has an identity and itâs movable."
l-values -> âIt has itâs own identity name. It lives till the end of the block either global or local variable."
gl-values -> âAbbreviated as âGenaralized l-valueâ. Its an l-value or an x-value."
r-values -> âAn r-value appears on the right hand side of the expression and itâs an x-value or a temporary object or a sub-object or an value that is not associated with an object.â
pr-values -> âItâs abbreviated as âpure r-valuesâ. It has no identity and itâs movable."

2. x-values
If an expression states: âa reference to Tâ then, the expression denotes an object or function denoted by the reference, and the expression is an lvalue or an x-value, depending on the expression. An expression is an x-value in the below-given scenarios:
2.1 Scenario 1: The result of calling a function whether explicitly or implicitly, whose return type is an rvalue reference to object type.
Letâs consider the below example where a function returns an rvalue reference and makes the expression an x-value.
|
|
In the preceding example, the functions balloon() and kite() returns rvalue references and that makes the calling expressions x-values. As the name denotes, If not returned, the rvalues declared inside the function will expire inside the functions but now we have it returned to the calling expressions in the main function. This behavior makes the calling expression an x-value (eXpiring values). We have extended the expiry of those rvalues by passing the references to the calling expression respectively.
2.2 Scenario 2: A cast to an rvalue reference to an object type
Casting an rvalue reference to an object type leads to an x-value expression. Here is an example:
|
|
In the preceding example, we do static_cast to store the address of an rvalue to a variable thus creating an rvalue reference. The whole expression is called an xvalue because it increases the lifetime of the rvalue beyond the declaration of it.
2.3 Scenario 3: A class member access expression designating a non-static data member in which the object expression is an xvalue
In this scenario, we need to write an expression that accesses the class data member that is not static. There are some factors which we need to consider while writing the expression. To understand that, we need to know how the âclass member access expressionâ looks like. It has two different parts, an object expression part (The part of expression before the dot operator) and the member identification part (The part of expression after the dot operator). The object expression part of the expression should be an xvalue and the member identification part should be a non-static member of the struct. In the below example, f().m; is an x-value expression because it satisfies the conditions we just discussed above.
|
|
2.4 Scenario 4: A .* pointer-to-member expression in which the first operand is an xvalue and the second operand is a pointer to data member
In this scenario, we need to write an expression that has xvalue as the first operand and it accesses the pointer to the data member declared inside the struct or class. Below is the example that does this.
|
|
In the above example, we have declared an xvalue expression get_xvalue().*p; in which the first operand get_xvalue() is an method that returns the rvalue reference to the object of struct C. Thus the calling expression in the main() becomes an xvalue because it increases the lifetime of an rvalue. This xvalue is used to access the *p thus makes the whole expression an xvalue.