In C++03, an expression is either an rvalue or an lvalue.
In C++11, an expression can be an:
- rvalue
- lvalue
- xvalue
- glvalue
- prvalue
Two categories have become five categories.
- What are these new categories of expressions?
- How do these new categories relate to the existing rvalue and lvalue categories?
- Are the rvalue and lvalue categories in C++0x the same as they are in C++03?
- Why are these new categories needed? Are the WG21 gods just trying to confuse us mere mortals?
C++03's categories are too restricted to capture the introduction of rvalue references correctly into expression attributes.
With the introduction of them, it was said that an unnamed rvalue reference evaluates to an rvalue, such that overload resolution would prefer rvalue reference bindings, which would make it select move constructors over copy constructors. But it was found that this causes problems all around, for example with Dynamic Types and with qualifications.
To show this, consider
On pre-xvalue drafts, this was allowed, because in C++03, rvalues of non-class types are never cv-qualified. But it is intended that
const
applies in the rvalue-reference case, because here we do refer to objects (= memory!), and dropping const from non-class rvalues is mainly for the reason that there is no object around.The issue for dynamic types is of similar nature. In C++03, rvalues of class type have a known dynamic type - it's the static type of that expression. Because to have it another way, you need references or dereferences, which evaluate to an lvalue. That isn't true with unnamed rvalue references, yet they can show polymorphic behavior. So to solve it,
unnamed rvalue references become xvalues. They can be qualified and potentially have their dynamic type different. They do, like intended, prefer rvalue references during overloading, and won't bind to non-const lvalue references.
What previously was an rvalue (literals, objects created by casts to non-reference types) now becomes an prvalue. They have the same preference as xvalues during overloading.
What previously was an lvalue stays an lvalue.
And two groupings are done to capture those that can be qualified and can have different dynamic types (glvalues) and those where overloading prefers rvalue reference binding (rvalues).
A C++03 lvalue is still a C++11 lvalue, whereas a C++03 rvalue is called a prvalue in C++11.
IMHO, the best explanation about its meaning gave us Stroustrup + take into account examples of Dániel Sándor and Mohan:
Stroustrup:
I'll start with your last question:
The C++ standard contains many rules that deal with the value category of an expression. Some rules make a distinction between lvalue and rvalue. For example, when it comes to overload resolution. Other rules make a distinction between glvalue and prvalue. For example, you can have a glvalue with an incomplete or abstract type but there is no prvalue with an incomplete or abstract type. Before we had this terminology the rules that actually need to distinguish between glvalue/prvalue referred to lvalue/rvalue and they were either unintentionally wrong or contained lots of explaining and exceptions to the rule a la "...unless the rvalue is due to unnamed rvalue reference...". So, it seems like a good idea to just give the concepts of glvalues and prvalues their own name.
We still have the terms lvalue and rvalue that are compatible with C++98. We just divided the rvalues into two subgroups, xvalues and prvalues, and we refer to lvalues and xvalues as glvalues. Xvalues are a new kind of value category for unnamed rvalue references. Every expression is one of these three: lvalue, xvalue, prvalue. A Venn diagram would look like this:
Examples with functions:
But also don't forget that named rvalue references are lvalues:
I guess this document might serve as a not so short introduction : n3055
The whole massacre began with the move semantics. Once we have expressions that can be moved and not copied, suddenly easy to grasp rules demanded distinction between expressions that can be moved, and in which direction.
From what I guess based on the draft, the r/l value distinction stays the same, only in the context of moving things get messy.
Are they needed? Probably not if we wish to forfeit the new features. But to allow better optimization we should probably embrace them.
Quoting n3055:
E
is an expression of pointer type, then*E
is an lvalue expression referring to the object or function to whichE
points. As another example, the result of calling a function whose return type is an lvalue reference is an lvalue.]The document in question is a great reference for this question, because it shows the exact changes in the standard that have happened as a result of the introduction of the new nomenclature.
The FCD (n3092) has an excellent description:
I suggest you read the entire section 3.10 Lvalues and rvalues though.
Again:
The semantics of rvalues has evolved particularly with the introduction of move semantics.
So that move construction/assignment could be defined and supported.