What Are Rvalues, Lvalues, Xvalues, Glvalues, and Prvalues?
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...
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?
13 Answers
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:
- An lvalue (so-called, historically,
because lvalues could appear on the
left-hand side of an assignment
expression) designates a function or
an object. [Example: If
Eis an expression of pointer type, then*Eis an lvalue expression referring to the object or function to whichEpoints. As another example, the result of calling a function whose return type is an lvalue reference is an lvalue.] - An xvalue (an “eXpiring” value) also refers to an object, usually near the end of its lifetime (so that its resources may be moved, for example). 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.]
- A glvalue (“generalized” lvalue) is an lvalue or an xvalue.
- An rvalue (so-called, historically, because rvalues could appear on the right-hand side of an assignment expression) is an xvalue, a temporary object or subobject thereof, or a value that is not associated with an object.
- A prvalue (“pure” rvalue) is an rvalue that is not an xvalue. [Example: The result of calling a function whose return type is not a reference is a prvalue]
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.
What are these new categories of expressions?
The FCD (n3092) has an excellent description:
— An lvalue (so called, historically, because lvalues could appear on the left-hand side of an assignment expression) designates a function or an object. [ Example: If E is an expression of pointer type, then *E is an lvalue expression referring to the object or function to which E points. As another example, the result of calling a function whose return type is an lvalue reference is an lvalue. —end example ]
— An xvalue (an “eXpiring” value) also refers to an object, usually near the end of its lifetime (so that its resources may be moved, for example). An xvalue is the result of certain kinds of expressions involving rvalue references (8.3.2). [ Example: The result of calling a function whose return type is an rvalue reference is an xvalue. —end example ]
— A glvalue (“generalized” lvalue) is an lvalue or an xvalue.
— An rvalue (so called, historically, because rvalues could appear on the right-hand side of an assignment expressions) is an xvalue, a temporary object (12.2) or subobject thereof, or a value that is not associated with an object.
— A prvalue (“pure” rvalue) is an rvalue that is not an xvalue. [ Example: The result of calling a function whose return type is not a reference is a prvalue. The value of a literal such as 12, 7.3e5, or true is also a prvalue. —end example ]
Every expression belongs to exactly one of the fundamental classifications in this taxonomy: lvalue, xvalue, or prvalue. This property of an expression is called its value category. [ Note: The discussion of each built-in operator in Clause 5 indicates the category of the value it yields and the value categories of the operands it expects. For example, the built-in assignment operators expect that the left operand is an lvalue and that the right operand is a prvalue and yield an lvalue as the result. User-defined operators are functions, and the categories of values they expect and yield are determined by their parameter and return types. —end note
I suggest you read the entire section 3.10 Lvalues and rvalues though.
How do these new categories relate to the existing rvalue and lvalue categories?
Again:
Are the rvalue and lvalue categories in C++0x the same as they are in C++03?
The semantics of rvalues has evolved particularly with the introduction of move semantics.
Why are these new categories needed?
So that move construction/assignment could be defined and supported.
I'll start with your last question:
Why are these new categories needed?
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.
What are these new categories of expressions? How do these new categories relate to the existing rvalue and lvalue categories?
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:
______ ______
/ X \
/ / \ \
| l | x | pr |
\ \ / /
\______X______/
gl r
Examples with functions:
int prvalue();
int& lvalue();
int&& xvalue();
But also don't forget that named rvalue references are lvalues:
void foo(int&& t) {
// t is initialized with an rvalue expression
// but is actually an lvalue expression itself
}
Why are these new categories needed? Are the WG21 gods just trying to confuse us mere mortals?
I don't feel that the other answers (good though many of them are) really capture the answer to this particular question. Yes, these categories and such exist to allow move semantics, but the complexity exists for one reason. This is the one inviolate rule of moving stuff in C++11:
Thou shalt move only when it is unquestionably safe to do so.
That is why these categories exist: to be able to talk about values where it is safe to move from them, and to talk about values where it is not.
In the earliest version of r-value references, movement happened easily. Too easily. Easily enough that there was a lot of potential for implicitly moving things when the user didn't really mean to.
Here are the circumstances under which it is safe to move something:
- When it's a temporary or subobject thereof. (prvalue)
- When the user has explicitly said to move it.
If you do this:
SomeType &&Func() { ... }
SomeType &&val = Func();
SomeType otherVal{val};
What does this do? In older versions of the spec, before the 5 values came in, this would provoke a move. Of course it does. You passed an rvalue reference to the constructor, and thus it binds to the constructor that takes an rvalue reference. That's obvious.
There's just one problem with this; you didn't ask to move it. Oh, you might say that the && should have been a clue, but that doesn't change the fact that it broke the rule. val isn't a temporary because temporaries don't have names. You may have extended the lifetime of the temporary, but that means it isn't temporary; it's just like any other stack variable.
If it's not a temporary, and you didn't ask to move it, then moving is wrong.
The obvious solution is to make val an lvalue. This means that you can't move from it. OK, fine; it's named, so its an lvalue.
Once you do that, you can no longer say that SomeType&& means the same thing everwhere. You've now made a distinction between named rvalue references and unnamed rvalue references. Well, named rvalue references are lvalues; that was our solution above. So what do we call unnamed rvalue references (the return value from Func above)?
It's not an lvalue, because you can't move from an lvalue. And we need to be able to move by returning a &&; how else could you explicitly say to move something? That is what std::move returns, after all. It's not an rvalue (old-style), because it can be on the left side of an equation (things are actually a bit more complicated, see this question and the comments below). It is neither an lvalue nor an rvalue; it's a new kind of thing.
What we have is a value that you can treat as an lvalue, except that it is implicitly moveable from. We call it an xvalue.
Note that xvalues are what makes us gain the other two categories of values:
A prvalue is really just the new name for the previous type of rvalue, i.e. they're the rvalues that aren't xvalues.
Glvalues are the union of xvalues and lvalues in one group, because they do share a lot of properties in common.
So really, it all comes down to xvalues and the need to restrict movement to exactly and only certain places. Those places are defined by the rvalue category; prvalues are the implicit moves, and xvalues are the explicit moves (std::move returns an xvalue).
IMHO, the best explanation about its meaning gave us Stroustrup + take into account examples of Dániel Sándor and Mohan:
Stroustrup:
Now I was seriously worried. Clearly we were headed for an impasse or a mess or both. I spent the lunchtime doing an analysis to see which of the properties (of values) were independent. There were only two independent properties:
has identity– i.e. and address, a pointer, the user can determine whether two copies are identical, etc.can be moved from– i.e. we are allowed to leave to source of a "copy" in some indeterminate, but valid stateThis led me to the conclusion that there are exactly three kinds of values (using the regex notational trick of using a capital letter to indicate a negative – I was in a hurry):
iM: has identity and cannot be moved fromim: has identity and can be moved from (e.g. the result of casting an lvalue to a rvalue reference)
Im: does not have identity and can be moved from.The fourth possibility,
IM, (doesn’t have identity and cannot be moved) is not useful inC++(or, I think) in any other language.In addition to these three fundamental classifications of values, we have two obvious generalizations that correspond to the two independent properties:
i: has identitym: can be moved fromThis led me to put this diagram on the board:
Must Read
Naming
I observed that we had only limited freedom to name: The two points to the left (labeled
iMandi) are what people with more or less formality have calledlvaluesand the two points on the right (labeledmandIm) are what people with more or less formality have calledrvalues. This must be reflected in our naming. That is, the left "leg" of theWshould have names related tolvalueand the right "leg" of theWshould have names related torvalue.I note that this whole discussion/problem arise from the introduction of rvalue references and move semantics. These notions simply don’t exist in Strachey’s world consisting of justrvaluesandlvalues. Someone observed that the ideas that
- Every
valueis either anlvalueor anrvalue- An
lvalueis not anrvalueand anrvalueis not anlvalueare deeply embedded in our consciousness, very useful properties, and traces of this dichotomy can be found all over the draft standard. We all agreed that we ought to preserve those properties (and make them precise). This further constrained our naming choices. I observed that the standard library wording uses
rvalueto meanm(the generalization), so that to preserve the expectation and text of the standard library the right-hand bottom point of theWshould be namedrvalue.This led to a focused discussion of naming. First, we needed to decide on
lvalue.ShouldlvaluemeaniMor the generalizationi? Led by Doug Gregor, we listed the places in the core language wording where the wordlvaluewas qualified to mean the one or the other. A list was made and in most cases and in the most tricky/brittle textlvaluecurrently meansiM. This is the classical meaning of lvalue because "in the old days" nothing was moved;moveis a novel notion inC++0x. Also, naming the topleft point of theWlvaluegives us the property that every value is anlvalueor anrvalue, but not both.So, the top left point of the
Wislvalueand the bottom right point isrvalue.What does that make the bottom left and top right points? The bottom left point is a generalization of the classical lvalue, allowing for move. So it is ageneralized lvalue.We named itglvalue.You can quibble about the abbreviation, but (I think) not with the logic. We assumed that in serious usegeneralized lvaluewould somehow be abbreviated anyway, so we had better do it immediately (or risk confusion). The top right point of the W is less general than the bottom right (now, as ever, calledrvalue). That point represent the original pure notion of an object you can move from because it cannot be referred to again (except by a destructor). I liked the phrasespecialized rvaluein contrast togeneralized lvaluebutpure rvalueabbreviated toprvaluewon out (and probably rightly so). So, the left leg of the W islvalueandglvalueand the right leg isprvalueandrvalue.Incidentally, every value is either a glvalue or a prvalue, but not both.This leaves the top middle of the
W:im; that is, values that have identity and can be moved. We really don’t have anything that guides us to a good name for those esoteric beasts. They are important to people working with the (draft) standard text, but are unlikely to become a household name. We didn’t find any real constraints on the naming to guide us, so we picked ‘x’ for the center, the unknown, the strange, the xpert only, or even x-rated.