What are rvalues, lvalues, xvalues, glvalues, and prvalues?
Asked Answered
U

14

1665

In C++03, an expression is either an rvalue or an lvalue.

In C++11, an expression can be an:

  1. rvalue
  2. lvalue
  3. xvalue
  4. glvalue
  5. 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?
Undersell answered 30/8, 2010 at 15:2 Comment(22)
Are rvalue and lvalue mutually exclusive? The expression x where x is int can be used either as an lvalue or an rvalue.Revulsion
@Philip Potter: In C++03? Yes. An lvalue can be used as an rvalue because there is a standard lvalue-to-rvalue conversion.Undersell
@Philip (In C++03) It doesn't matter how it's used; it can only be one of the two. If you can assign to it, it's an lvalue, otherwise, it's an rvalue. Being an lvalue doesn't mean you can't use in on the right side of an expression, and being used on the right side of an expression does not by itself make something an rvalue.Arabella
@Tyler: "If you can assign to it, it's an lvalue, otherwise, it's an rvalue." -> Wrong, you can assign to class rvalues: string("hello") = string("world").Zenithal
Actually that works because you can call non-const members (such as std::string::operator=(std::string const&)) on temporaries. But assignment to UDT's is a bit tricky to understand fully.Checklist
Note that this is the value category. There are more properties that expressions can have. These include bit-field (true/false), temporary (true/false) and type (the type of it).Utta
fwiw, I found this article: eli.thegreenplace.net/2011/12/15/… It may be of some help to someone in the future. imho, it isn't too complicated and it isn't too simple. It actually goes into a little depth/explanation but does so in an understandable way. It also mentions some stuff about c++11. hihManchukuo
I think Fred's link above is better than any of the answers here. The link is dead, though. It was moved to: stroustrup.com/terminology.pdfSignalment
in C++ even your types have typesHomage
I notice you have not accepted an answer here, are the current answers not satisfactory? If so what would you like to see in an answer?Swick
@ShafikYaghmour: I like the collection of answers; several have valuable insights. I don't plan to accept an answer. If you have something to add, please feel free to do so.Undersell
I found this tutorial excellent: blog.smartbear.com/development/… (for the entire series see blog.smartbear.com/author/danny-kalev)Handedness
@JamesMcNellis: why you have don't plan to accept an answer? Then why you asked the question?Worry
@PravasiMeet As I noted in my previous comment, I like the collection of answers. Several answers offer valuable insights. I don't intend to pick one over the others.Undersell
I know it's a little late but here's a short and clear explanation: blog.knatten.org/2018/03/09/…Darmstadt
In fact, in C++11, a value is still either an rvalue or an lvalue. xvalue and prvalue are the two (disjoint) partitions of rvalue, and glvalue is the union of lvalue and xvalue.Heelandtoe
This reference is a great resouece.Homan
This too is awesome for the clarity of explanation. Pictures included.Liquescent
Your question has 1444 upvotes. Please accept an answer for the shake of newcomming peasants.Sandbox
My favorite quick explanation: accu.org/journals/overload/27/150/knatten_2641Contend
This Microsoft.com article is decent. There is also an IBM.com article.Cornerstone
@JerryAjay not only is this article nothing more than a cumbersome paraphrase of Stroustrup's succinct 5-page PDF, but it ALSO contains factual errors (I counted at least four). Just read Stroustrup.Carsoncarstensz
T
760

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 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.]
  • 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.

Tonga answered 30/8, 2010 at 15:9 Comment(9)
Thanks, this answer is really helpful! But my compiler doesn't agree with your examples for xvalues and prvalues; they are the exact opposite. Returning by rvalue reference gives me a prvalue, and returning by value gives me an xvalue. Did you get them mixed up, or is my test bed broken? I tried this with GCC 4.6.1, clang (from svn) and MSVC, and they all show the same behavior.Cater
Oops, I just followed the link and noticed that the examples are in the source. I'll go find my copy of the standard and check what it says...Cater
I use the macros from here to test various expressions: https://mcmap.net/q/15709/-how-to-test-whether-expression-is-a-temporary It could be that they misdiagnose things.Cater
Adding the xvalue isn't for the move semantics. Only with both of lvalue and rvalue, the move semantics, perfect forward and rvalue reference still are work well. I think the xvalue is just for the decltype operator: if the operand expression is xvalue, the decltype give the type of rvalue reference.Levan
Wait? Why does it say (in n3055) that this is false: "Every expression is either an lvalue or an rvalue". While Bjarne says that it is true (in his book "C++ Programming Language 4th Edition C+11"). From the book: "Note that every expression is either an lvalue or an rvalue, but not both."Psychopharmacology
@MuhamedCicak "Every expression is either an lvalue or an rvalue": it is true; and the standard (or the document n3055) doesn't say it's false. The reason this sentence was crossed out is that you were looking at changes between two versions of the document. The sentence was removed because it became superfluous after a more precise explanation was added.Garald
@Levan Not sure I understand - I found some examples of xvalues (https://mcmap.net/q/15710/-what-expressions-create-xvalues) and among them is move(x). How do you move without xvalue? Did you really mean "xvalue isn't for the move semantics" (at all), or "isn't just"? I'm catching up.Conscientious
what does "function whose return type is an __value reference" mean -- why "reference"?Simulcast
My friends, we have officially gone bananas.Integrated
S
376

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:

Taxonomy

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.

Springlet answered 30/8, 2010 at 15:2 Comment(7)
I like the diagram here. I think it might be useful to start the answer with "Every expression belongs to exactly one of the fundamental classifications in this taxonomy: lvalue, xvalue, or prvalue." Then it's easy to use the diagram to show those three fundamental classes are combined to make glvalue and rvalue.Cords
"is glvalue" is equivalent to "is not prvalue", and "is rvalue" is equivalent to "is not lvalue".Ferial
This one helped me the most: bajamircea.github.io/assets/2016-04-07-move-forward/… (Venn diagram of value categories)Conscientious
@AaronMcDaid Hi, quick question if you/someone can answer... Why not name glvalue as lvalue and lvalue as plvalue, to be consistent?Homan
@JohnP thank, you, the venn diagrams finally let me understand what these taxonomy graphs are saying. It's maddening that all these documents prsent the taxonomy graph without even saying what the arrows mean; that was leaving me completely in the dark.Aardvark
@VijayChavda one of the benefits of this naming is that it is still true that every expression is an lvalue or rvalue but not both. If you name glvalue as lvalue, this breaks. It is explained in a previous answer.Mona
This diagram also shows that it is still true that everything is either an lvalue or an rvalueNotable
T
210

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
}
Tevere answered 31/8, 2010 at 8:8 Comment(3)
From my understanding there is a small typo in this response. Xvalues are a new kind of value category for unnamed rvalue references. I believe it should be xvalues are named rvalue references. Unnamed rvalues are prvalues.Mona
@MatiasGrioni: A named rvalue recerence as an expression is an lvalue whereas an unnamed rvalue reference (such as returned by a function) is an rvalue.Tevere
At the time my understanding was underdeveloped and I think my terminology was not consistent (when I thought of name I was thinking of identify not actual variable name). The original answer has no typo and is correct.Mona
B
201

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:

  1. When it's a temporary or subobject thereof. (prvalue)
  2. 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).

Barogram answered 4/3, 2012 at 6:32 Comment(11)
This is interesting but does it compile? Shouldn't Func have a return statement?Soursop
@Thomas: It's an example; it doesn't matter how it creates the return value. What matters is that it returns a &&.Barogram
Note: prvalues can be on the left-hand side of an equation, also - as in X foo(); foo() = X; ... For this fundamental reason, I can't quite follow the above excellent answer through to the end, because you really only make the distinction between the new xvalue, and the old-style prvalue, based on the fact that it can be on the lhs.Insouciant
@DanNissenbaum: "as in X foo(); foo() = X;" I don't understand how that's valid code. What are X and foo? Is one of those a function?Barogram
X being a class; X foo(); being a function declaration, and foo() = X(); being a line of code. (I left off the second set of parentheses in foo() = X(); in my above comment.) For a question I just posted with this usage highlighted, see stackoverflow.com/questions/15482508/…Insouciant
xvalue cannot be on the left-hand side of assignment expression, nor get the address by the & operator. I think xvalue is only used for the definition of decltype ! without the xvalue, move semantics and perfect forward work well too.Levan
I think the answer would be significantly improved if the phrase It's not an rvalue (old-style), because it can be on the left side of an equation were changed to It's not an rvalue (old-style), because the old way of thinking about rvalues didn't really refer to the return values of function calls. I pointed out that prvalues can be on the left-hand side, and @ligand's pointed out that xvalues cannot be on the left-hand side - so not only is the current wording misleading, but it's also incorrect. I've had to stare at it awhile to overcome it within an otherwise outstanding answer.Insouciant
@DanNissenbaum "xvalue cannot be on the left-hand side of assignment expression" - why not? See ideone.com/wyrxiTFic
@Levan - Mikhail - Good point! xvalue vs. prvalue still confuses me. It made sense at the time when ligand wrote xvalue cannot be on the left-hand side of assignment expression - but looking at this fresh and seeing your code - it seems an xvalue can be on the left-hand side, unless gcc compiles this despite its not being defined in the standard...Insouciant
Thank you so much for this answer @NicolBolas, it's the only one I have come across so far that explains why the xvalue category is needed. If possible, could you please also elucidate the meaning of the official definition of xvalue: an xvalue is a glvalue that denotes an object whose resources can be reused. What is meant by "resources can be reused" here?Flowery
Does "reuse" really mean "claim", as in an xvalue's resources can be claimed by another object?Flowery
K
185

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 state

This 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 from
  • im: 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 in C++ (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 identity
  • m: can be moved from

This led me to put this diagram on the board: enter image description here

Naming

I observed that we had only limited freedom to name: The two points to the left (labeled iM and i) are what people with more or less formality have called lvalues and the two points on the right (labeled m and Im) are what people with more or less formality have called rvalues. This must be reflected in our naming. That is, the left "leg" of the W should have names related to lvalue and the right "leg" of the W should have names related to rvalue. 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 just rvalues and lvalues. Someone observed that the ideas that

  • Every value is either an lvalue or an rvalue
  • An lvalue is not an rvalue and an rvalue is not an lvalue

are 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 rvalue to mean m (the generalization), so that to preserve the expectation and text of the standard library the right-hand bottom point of the W should be named rvalue.

This led to a focused discussion of naming. First, we needed to decide on lvalue. Should lvalue mean iM or the generalization i? Led by Doug Gregor, we listed the places in the core language wording where the word lvalue was qualified to mean the one or the other. A list was made and in most cases and in the most tricky/brittle text lvalue currently means iM. This is the classical meaning of lvalue because "in the old days" nothing was moved; move is a novel notion in C++0x. Also, naming the topleft point of the W lvalue gives us the property that every value is an lvalue or an rvalue, but not both.

So, the top left point of the W is lvalue and the bottom right point is rvalue. 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 a generalized lvalue. We named it glvalue. You can quibble about the abbreviation, but (I think) not with the logic. We assumed that in serious use generalized lvalue would 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, called rvalue). 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 phrase specialized rvalue in contrast to generalized lvalue but pure rvalue abbreviated to prvalue won out (and probably rightly so). So, the left leg of the W is lvalue and glvalue and the right leg is prvalue and rvalue. 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.

Steve showing off the final product

Kenwee answered 3/7, 2016 at 12:30 Comment(5)
yep, it's better to read original proposals and discussions of the C++ comitee, than the standard, if you want to understand what they meant :DKenwee
Literals don't have identity and can't be moved from; they're nonetheless useful.Lintwhite
I just want to clarify a thing. int&& f(){ return 1; } and MyClass&& g(){ return MyClass(); } return xvalue, right? Then where can I find the identity of the expressions f(); and "g();"? They have identity, because there is another expression in the return statement, that refers to the same object as they refer to - do I understand it right?Annabel
@Lintwhite According to the standard: string literals are lvalues, all other literals are prvalues. Strictly speaking you could make an argument for saying non-string literals should be immovable, but that's not how the standard is written.Rolfston
@DrPizza: "Can be moved from" means "can be bound to by an rvalue reference." Literals are rvalues, as rvalue references can bind to them, and specifically they are prvalues, as they have no identity. int &&r = 42; is valid because the expression 42 is an rvalue. An expression that has no identity and cannot be moved from is useless because no pointer could ever point to it, and no reference could ever bind to it, so it would be impossible to pass it as an argument to a function. (Pass-by-value requires copy construction, which logically requires binding a reference to the source value.)Norbertonorbie
H
87

INTRODUCTION

ISOC++11 (officially ISO/IEC 14882:2011) is the most recent version of the standard of the C++ programming language. It contains some new features, and concepts, for example:

  • rvalue references
  • xvalue, glvalue, prvalue expression value categories
  • move semantics

If we would like to understand the concepts of the new expression value categories we have to be aware of that there are rvalue and lvalue references. It is better to know rvalues can be passed to non-const rvalue references.

int& r_i=7; // compile error
int&& rr_i=7; // OK

We can gain some intuition of the concepts of value categories if we quote the subsection titled Lvalues and rvalues from the working draft N3337 (the most similar draft to the published ISOC++11 standard).

3.10 Lvalues and rvalues [basic.lval]

1 Expressions are categorized according to the taxonomy in Figure 1.

  • 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 expression) 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.

But I am not quite sure about that this subsection is enough to understand the concepts clearly, because "usually" is not really general, "near the end of its lifetime" is not really concrete, "involving rvalue references" is not really clear, and "Example: The result of calling a function whose return type is an rvalue reference is an xvalue." sounds like a snake is biting its tail.

PRIMARY VALUE CATEGORIES

Every expression belongs to exactly one primary value category. These value categories are lvalue, xvalue and prvalue categories.

lvalues

The expression E belongs to the lvalue category if and only if E refers to an entity that ALREADY has had an identity (address, name or alias) that makes it accessible outside of E.

#include <iostream>

int i=7;

const int& f(){
    return i;
}

int main()
{
    std::cout<<&"www"<<std::endl; // The expression "www" in this row is an lvalue expression, because string literals are arrays and every array has an address.  

    i; // The expression i in this row is an lvalue expression, because it refers to the same entity ...
    i; // ... as the entity the expression i in this row refers to.

    int* p_i=new int(7);
    *p_i; // The expression *p_i in this row is an lvalue expression, because it refers to the same entity ...
    *p_i; // ... as the entity the expression *p_i in this row refers to.

    const int& r_I=7;
    r_I; // The expression r_I in this row is an lvalue expression, because it refers to the same entity ...
    r_I; // ... as the entity the expression r_I in this row refers to.

    f(); // The expression f() in this row is an lvalue expression, because it refers to the same entity ...
    i; // ... as the entity the expression f() in this row refers to.

    return 0;
}

xvalues

The expression E belongs to the xvalue category if and only if it is

— the result of calling a function, whether implicitly or explicitly, whose return type is an rvalue reference to the type of object being returned, or

int&& f(){
    return 3;
}

int main()
{
    f(); // The expression f() belongs to the xvalue category, because f() return type is an rvalue reference to object type.

    return 0;
}

— a cast to an rvalue reference to object type, or

int main()
{
    static_cast<int&&>(7); // The expression static_cast<int&&>(7) belongs to the xvalue category, because it is a cast to an rvalue reference to object type.
    std::move(7); // std::move(7) is equivalent to static_cast<int&&>(7).

    return 0;
}

— a class member access expression designating a non-static data member of non-reference type in which the object expression is an xvalue, or

struct As
{
    int i;
};

As&& f(){
    return As();
}

int main()
{
    f().i; // The expression f().i belongs to the xvalue category, because As::i is a non-static data member of non-reference type, and the subexpression f() belongs to the xvlaue category.

    return 0;
}

— a pointer-to-member expression in which the first operand is an xvalue and the second operand is a pointer to data member.

Note that the effect of the rules above is that named rvalue references to objects are treated as lvalues and unnamed rvalue references to objects are treated as xvalues; rvalue references to functions are treated as lvalues whether named or not.

#include <functional>

struct As
{
    int i;
};

As&& f(){
    return As();
}

int main()
{
    f(); // The expression f() belongs to the xvalue category, because it refers to an unnamed rvalue reference to object.
    As&& rr_a=As();
    rr_a; // The expression rr_a belongs to the lvalue category, because it refers to a named rvalue reference to object.
    std::ref(f); // The expression std::ref(f) belongs to the lvalue category, because it refers to an rvalue reference to function.

    return 0;
}

prvalues

The expression E belongs to the prvalue category if and only if E belongs neither to the lvalue nor to the xvalue category.

struct As
{
    void f(){
        this; // The expression this is a prvalue expression. Note, that the expression this is not a variable.
    }
};

As f(){
    return As();
}

int main()
{
    f(); // The expression f() belongs to the prvalue category, because it belongs neither to the lvalue nor to the xvalue category.

    return 0;
}

MIXED VALUE CATEGORIES

There are two further important mixed value categories. These value categories are rvalue and glvalue categories.

rvalues

The expression E belongs to the rvalue category if and only if E belongs to the xvalue category, or to the prvalue category.

Note that this definition means that the expression E belongs to the rvalue category if and only if E refers to an entity that has not had any identity that makes it accessible outside of E YET.

glvalues

The expression E belongs to the glvalue category if and only if E belongs to the lvalue category, or to the xvalue category.

A PRACTICAL RULE

Scott Meyer has published a very useful rule of thumb to distinguish rvalues from lvalues.

  • If you can take the address of an expression, the expression is an lvalue.
  • If the type of an expression is an lvalue reference (e.g., T& or const T&, etc.), that expression is an lvalue.
  • Otherwise, the expression is an rvalue. Conceptually (and typically also in fact), rvalues correspond to temporary objects, such as those returned from functions or created through implicit type conversions. Most literal values (e.g., 10 and 5.3) are also rvalues.
Hypotrachelium answered 20/1, 2016 at 13:46 Comment(11)
I still don't get gvalue :( , It would have helped if you had provided awesome examples like you did for other categories :)Pilaf
All examples for lvalues and all examples for xvalues are examples for glvalues as well. Thank you for editing!Annabel
Then why was gvalue introduced in standard I wonder? , I mean then only lvalue, rvalue , xvalue , and prvalue would have sufficed . Thanks again :)Pilaf
You are right. The three primary value categories are sufficed. Rvalue is not neccessary either. I think rvalue and glvalue is in the standard for convenience.Annabel
Had a hard time to understand struct As{void f(){this;}} the this variable is a prvalue. I thought this should be a lvalue. Until the standard 9.3.2 says: In the body of a non-static (9.3) member function, the keyword this is a prvalue expression.Middleton
@r0ng this is a prvalue but *this is an lvalueAffray
"www" doesn't always have the same address. It is an lvalue because it is an array.Readjustment
You could fix that f(); // The expression f() in this row is an lvalue expression, because it refers to the same entity ... i; // ... as the entity the expression f() in this row refers to. Sandbox
"The expression E belongs to the xvalue category if and only if it is: 1) the result of calling a function, whether implicitly or explicitly, whose return type is an rvalue reference to the type of object being returned, or 2) ... 3) ... 4) ..." Since C++17: 5) any expression that designates a temporary object, after temporary materialization is xvalue expression. Can you add it to your answer and provide an example?Expire
The expression i in this row is an lvalue expression, because it refers to the same entity as the entity the expression i in this row refers to sounds even more like a snake is biting its tail. I would say this snake has swallowed itself completely.Gerek
This is a very explanatory answer.Cyclograph
E
54

I have struggled with this for a long time, until I came across the cppreference.com explanation of the value categories.

It is actually rather simple, but I find that it is often explained in a way that's hard to memorize. Here it is explained very schematically. I'll quote some parts of the page:

Primary categories

The primary value categories correspond to two properties of expressions:

  • has identity: it's possible to determine whether the expression refers to the same entity as another expression, such as by comparing addresses of the objects or the functions they identify (obtained directly or indirectly);

  • can be moved from: move constructor, move assignment operator, or another function overload that implements move semantics can bind to the expression.

Expressions that:

  • have identity and cannot be moved from are called lvalue expressions;
  • have identity and can be moved from are called xvalue expressions;
  • do not have identity and can be moved from are called prvalue expressions;
  • do not have identity and cannot be moved from are not used.

lvalue

An lvalue ("left value") expression is an expression that has identity and cannot be moved from.

rvalue (until C++11), prvalue (since C++11)

A prvalue ("pure rvalue") expression is an expression that does not have identity and can be moved from.

xvalue

An xvalue ("expiring value") expression is an expression that has identity and can be moved from.

glvalue

A glvalue ("generalized lvalue") expression is an expression that is either an lvalue or an xvalue. It has identity. It may or may not be moved from.

rvalue (since C++11)

An rvalue ("right value") expression is an expression that is either a prvalue or an xvalue. It can be moved from. It may or may not have identity.

So let's put that into a table:

Can be moved from (= rvalue) Cannot be moved from
Has identity (= glvalue) xvalue lvalue
No identity prvalue not used
Excrescency answered 17/6, 2016 at 2:20 Comment(5)
In some books, xvalues are shown to have their x come from "expert" or "exceptional"Presbyopia
And more importantly, their all-comprehensive example list.Voyles
Kris van Res explains the table in his talk: youtu.be/km3Urog_wzk?t=868Twelve
I was looking for this table, this one explains a lot in a concise wayGerek
Thanks for the table here, but still confused about why the "this" pointer is a prvalue rather than a lvalue... Could someone explain a little bit?Waldemar
U
36

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

int const&& f();

int main() {
  int &&i = f(); // disgusting!
}

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).

Utta answered 30/8, 2010 at 16:46 Comment(1)
the answer is obviously reasonable. xvalue is just rvalue which can be cv-qualified and dynamic typed!Levan
V
33

These are terms that the C++ committee used to define move semantics in C++11. Here's the story.

I find it difficult to understand the terms given their precise definitions, the long lists of rules or this popular diagram:

value categories traditional diagram

It's easier on a Venn diagram with typical examples:

value categories Venn diagram

Basically:

  • every expression is either lvalue or rvalue
  • lvalue must be copied, because it has identity, so can be used later
  • rvalue can be moved, either because it's a temporary (prvalue) or explicitly moved (xvalue)

Now, the good question is that if we have two orthogonal properties ("has identity" and "can be moved"), what's the fourth category to complete lvalue, xvalue and prvalue? That would be an expression that has no identity (hence cannot be accessed later) and cannot be moved (one need to copy its value). This is simply not useful, so hasn't been named.

Vocational answered 15/3, 2021 at 15:20 Comment(2)
This is crystal clear, and is the only clear answer I've ever seen. Yes, my experience matches what you describe exactly; in particular, the popular diagram is unhelpful for learning what's going on, since it's meaningless unless one already understands the relationships and, essentially, has the venn diagram in their head.Aardvark
Nice. I'd change the clause "lvalue must be copied, because it has identity" though to "lvalue must not be moved ...", to be more precise (less misleading actually), and also remove the "because it has identity" part, because that seems incorrect: xvalues also have identity, yet they are not copied, but moved. (Having an identity is unfortunately a less intuitive trait than most explanations suggest.) Then I'd upvote.Pterous
W
26

As the previous answers exhaustively covered the theory behind the value categories, there is just another thing I'd like to add: you can actually play with it and test it.

For some hands-on experimentation with the value categories, you can make use of the decltype specifier. Its behavior explicitly distinguishes between the three primary value categories (xvalue, lvalue, and prvalue).

Using the preprocessor saves us some typing ...

Primary categories:

#define IS_XVALUE(X) std::is_rvalue_reference<decltype((X))>::value
#define IS_LVALUE(X) std::is_lvalue_reference<decltype((X))>::value
#define IS_PRVALUE(X) !std::is_reference<decltype((X))>::value

Mixed categories:

#define IS_GLVALUE(X) (IS_LVALUE(X) || IS_XVALUE(X))
#define IS_RVALUE(X) (IS_PRVALUE(X) || IS_XVALUE(X))

Now we can reproduce (almost) all the examples from cppreference on value category.

Here are some examples with C++17 (for terse static_assert):

void doesNothing(){}
struct S
{
    int x{0};
};
int x = 1;
int y = 2;
S s;

static_assert(IS_LVALUE(x));
static_assert(IS_LVALUE(x+=y));
static_assert(IS_LVALUE("Hello world!"));
static_assert(IS_LVALUE(++x));

static_assert(IS_PRVALUE(1));
static_assert(IS_PRVALUE(x++));
static_assert(IS_PRVALUE(static_cast<double>(x)));
static_assert(IS_PRVALUE(std::string{}));
static_assert(IS_PRVALUE(throw std::exception()));
static_assert(IS_PRVALUE(doesNothing()));

static_assert(IS_XVALUE(std::move(s)));
// The next one doesn't work in gcc 8.2 but in gcc 9.1. Clang 7.0.0 and msvc 19.16 are doing fine.
static_assert(IS_XVALUE(S().x)); 

The mixed categories are kind of boring once you figured out the primary category.

For some more examples (and experimentation), check out the following link on compiler explorer. Don't bother reading the assembly, though. I added a lot of compilers just to make sure it works across all the common compilers.

Whoreson answered 14/2, 2019 at 16:10 Comment(1)
I think #define IS_GLVALUE(X) IS_LVALUE(X) || IS_XVALUE(X) should actually be #define IS_GLVALUE(X) (IS_LVALUE(X) || IS_XVALUE(X)) otherwise look at what happens if you && two IS_GLVALUE.Lusterware
Z
20

How do these new categories relate to the existing rvalue and lvalue categories?

A C++03 lvalue is still a C++11 lvalue, whereas a C++03 rvalue is called a prvalue in C++11.

Zenithal answered 30/8, 2010 at 15:45 Comment(0)
S
17

One addendum to the excellent answers above, on a point that confused me even after I had read Stroustrup and thought I understood the rvalue/lvalue distinction. When you see

int&& a = 3,

it's very tempting to read the int&& as a type and conclude that a is an rvalue. It's not:

int&& a = 3;
int&& c = a; //error: cannot bind 'int' lvalue to 'int&&'
int& b = a; //compiles

a has a name and is ipso facto an lvalue. Don't think of the && as part of the type of a; it's just something telling you what a is allowed to bind to.

This matters particularly for T&& type arguments in constructors. If you write

Foo::Foo(T&& _t) : t{_t} {}

you will copy _t into t. You need

Foo::Foo(T&& _t) : t{std::move(_t)} {} if you want to move. Would that my compiler warned me when I left out the move!

Smokedry answered 25/7, 2016 at 4:26 Comment(1)
I think this answer could be clarified. "What a is allowed to bind to": Sure, but in line 2 & 3 your variables are c & b, and it's not a which binds to, and the type of a is irrelevant here, isn't it? The lines would be the same if a was declared int a. The actual main difference here is that in line 1 a doesn't have to be const to bind to 3.Excrescency
S
14

This is Venn diagram I made for a highly visual C++ book I'm writing which I will be publishing on leanpub during development soon.

Venn Diagram showing the relationship between the value categories in C++

The other answers go into more detail with words, and show similar diagrams. But hopefully this presentation of the information is fairly complete and useful for referencing, in addition.

The main takeaway for me on this topic is that expressions have these two properties: identity and movability. The first deals with the the "solidness" with which something exists. That's important because the C++ abstract machine is allowed to and encouraged to aggressively change and shrink your code through optimizations, and that means that things without identity might only ever exist in the mind of the compiler or in a register for a brief moment before getting trampled on. But a piece of data like that is also guaranteed not to cause issues if you recycle it's innards since there's no way to try to use it. And thus, move semantics were invented to allow us to capture references to temporaries, upgrading them to lvalues and extending their lifetime.

Move semantics originally were about not just throwing away temporaries wastefully, but instead giving them away so they can consumed by another.

When you want to eat the rest of your friend's cornbread so it don't go to waste.

When you give your cornbread away, the person you give it to now owns it. They consume it. You should not attempt to eat or digest said cornbread once you've given it away. Maybe that cornbread was headed for the trash anyway, but now it's headed for their bellies. It's not yours anymore.

In C++ land, the idea of "consuming" a resource means that resource is now owned by us and so we should do any cleanup necessary, and ensure the object isn't accessed elsewhere. Often times, that means borrowing the guts to create new objects. I call that "donating organs". Usually, we are talking about pointers or references contained by the object, or something like that, and we want to keep those pointers or references around because they refer to data elsewhere in our program that is not dying.

Thus you could write a function overload that takes an rvalue reference, and if a temporary (prvalue) were passed in, that's the overload that would be called. A new lvalue would be created upon binding to the rvalue reference taken by the function, extending the life of the temporary so you could consume it within your function.

At some point, we realized that we often had lvalue non-temporary data that we were finished with in one scope, but wanted to cannibalize in another scope. But they aren't rvalues and so wouldn't bind to an rvalue reference. So we made std::move, which is just a fancy cast from lvalue to rvalue reference. Such a datum is an xvalue: a former lvalue now acting as if it were a temporary so it can also be moved from.

Sawbuck answered 9/9, 2021 at 20:55 Comment(5)
Consider duplicating the content as text, for reasons outlined here. Regarding xvalues: tbe result of std::move is an xvalue, though the object it refers to isn't necessarily going to die soon.Hyacinthus
Unfortunately, that would destroy the point of this graphic which was that I struggled to remember and process this information over years of (kinda) knowing it because my brain needs a diagram instead of a wall of text to hang onto. But you're right that if this was the primary answer, it should be more text-oriented. I hope that's okay for this answer. Just hoping to help someone else.Sawbuck
"which I will be publishing on leanpub during development soon". Have you finished it?Carsoncarstensz
"xvalues have identity", how do we say that an expression like "std::move(3)", which according to the standard must be an xvalue expression, has an identity? It is not bound to anything and does not have a name.Cyclograph
Ugh, tbh. Haha. This is a hard corner of the language to teach. The hardest, imo. References are the well-intentioned construction material used to pave the road to hell.Sawbuck
U
0

In languages without an assignment command, such as mathematics, the value of an expression (e.g. x + 1) remains the same within its scope. That important language property is called definiteness. However in languages with an assignment command, such as C++, the value of an expression can vary within its scope under assignment; actually the locations involved in the value remain the same and it is their contents which can vary. So to preserve definiteness in those languages, a new type of value should be introduced: locations.

For that reason, in 1967, Christopher Strachey coined the terms L-value and R-value in his influential set of lecture notes Fundamental Concepts in Programming Languages while developing the CPL programming language:

  • L-value: a location in the store of the machine;
  • R-value: a value (it can be the content of a location and can be itself a location).

All expressions have an R-value but only some of them also have an L-value:

  • L-value expression: expression that has an L-value;
  • R-value expression: expression that doesn’t have an L-value.

In 2010, Bjarne Stroustrup further refined those expression categories in his informal C++ standards committee note ’New’ Value Terminology to take move semantics into account while developing the C++ programming language:

  • L-value expression: expression that has an L-value and that cannot always be moved from (e.g. i in int j = i;, c in C d = c;, c.m;, c in return c;, c in throw c;, f in f(););
  • X-value expression: expression that has an L-value and that can always be moved from (e.g. C{}.m in std::cout << C{}.m;);
  • PR-value expression: expression that doesn’t have an L-value and that can always be moved from (e.g. 1 in int i = 1;, C{} in C c = C{};, 1 in i = 1;);
  • GL-value expression: L-value or X-value expression;
  • R-value expression: PR-value or X-value expression.

In 2015, Richard Smith updated the PR-value expression category in his C++ standards committee paper Guaranteed Copy Elision through Simplified Value Categories to take mandatory move elision into account while developing the C++ programming language (PR-value expressions are no longer moved from):

  • PR-value expression: expression that doesn’t have an L-value and that is used for initialization (e.g. 1 in int i = 1;, C{} in C c = C{};, 1 in i = 1;).
Urfa answered 13/7, 2023 at 19:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.