About this section, there are three important points
Academic definition of xvalue.
Practical expressions which are xvalue.
Relationship between xvalue and rvalue reference.
Statement and expression are two important conceptions, you can see their
definition in cppreference.com to see academic explanation. Expression:
Something which evaluates to a value. Example: 1+2/x Statement: A line of
code which does something. Example: GOTO 100; and statements are all
end with semi-comma. All expressions yield a value, So expression isa value, statement is an action.
And function call is a expression, because it can yield a value.
The designers of C realized that no harm was done if you were allowed to
evaluate an expression and throw away the result. In C, every syntactic
expression can be a made into a statement just by tacking a semicolon along
the end:
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 type, and each expression belongs
to exactly one of the three primary value categories: lvalue, prvalue, and
xvalue;
lvalue is not defined "can be put on the left of =". Because const int a is
also a lvalue, and you can’t put a on the left side of = . It has three
characteristics:
lvalue has Identity, (can get address by & operator),
lvalue can be persist beyond the expression.
lvalue can’t be move(stolen), because you need to keep original
one intact.
On the contrary, prvalue has no identity, and will not persist beyond
expression and can be move(stolen)
Remember that any expression that evaluates to an lvalue reference
(e.g., a function call, an overloaded assignment operator, etc.) is
an lvalue. Any expression that returns an object by value is anrvalue.
An xvalue is the result of certain kinds of expressions involving rvalue
references. [Example: The result of calling a function whose return type is
an rvalue reference is an xvalue.]
xvalue has identity and persist, and will persist beyond expression and can
be move(stolen). it usually near the end of its lifetime (so that its resources
may be moved, for example).
First, we can use persist and identity to classify value into lvalue and
rvalue, then c++11 introduce rvalue reference. rref can persist and move
at the same time. So we divide lvalue into lvalue and xvalue. and give them
new name. lvalue+xvalue = glvalue(persist) and xvalue + prvalue =
rvalue(move).
Any value must be one of three, lvalue, xvalue, or prvalue. These
three categories are complementary. lvalue pay attention to identityand persist, rvalue=(xvalue + prvalue) shout "I can be moved"loudly. So we call && rvalue reference, don’t call it xvaluereference.
To know this conception can help you to understand decltype. Detail can be
seen in the last chapter.
Summary table:
persist(Identity)
move
lvalue
Yes
No
pvalue
No
Yes
xvalue
Yes
Yes
Below I will talk about "Practical expressions which are xvalue" . In
definition, xvalue is just value with Identity and can be movable. In reallife, it’s return value of std::move() or static_cast<A&&>. A
better introduction can be seen: " C++11 Tutorial: Explaining the
Ever-Elusive Lvalues and Rvalues"
There are two common ways to get an xvalue expression: 1) Use
std::move to move an object. or 2) Use std::forward to forward an
rvalue.
Use std::forward to forward an rvalue. std::forward is typically used in a
function template to enable perfect forwarding of a function argument. If
the argument provided to the function template was an rvalue, the
parameter type will be an rvalue reference, which is an lvalue. In this case,
std::forward performs a static_cast to an rvalue reference type and returns
the rvalue reference.
(Note: If the argument provided to the function template was an lvalue, the
parameter type will be an lvalue reference and std::forward will return an
lvalue reference.)
Below I talk about "relationship between xvalue and rvalue reference".
xvalue is defined by rvalue reference. but rvalue reference has nodirect relationship with xvalue. You can’t think that a rvaluereference is a xvalue.
rvalue reference can only bind to rvalue, and rvalue is composed of prvalue+
xvalue. A plain reference can only bind to lvalue. Const lvalue reference can
bind to rvalue, but you can’t change it.
You need to know, previous codes and explanations just give the basic idea
of rvalue reference. Just like function pointer, we never use function pointer
in simple way, instead, we use it as a function argument to implement call
back. For rvalue reference, We just use it as move semantic. I will
explain it in the next section.