Question

This question is great because it has answers on what are the differences between rvalue, lvalue, xvalue, glvalue, and prvalue. The top answer has a decent explanation of each, and I understand their differences when I read them. However, I'm having a hard time keeping them straight in my head, and I have to google them every time someone uses these terms to remind myself which one is which.

Are there any common mnemonics or other ways people remember which one is which? I'd really like to be able to keep them all straight in my head without mixing them up as I currently do.

Was it helpful?

Solution

I make 2 associations:

  • you can only take the address of an lvalue
  • xvalues is what an std::move expression is

If it's neither then it's probably a prvalue.

Now, to remember glvalues and rvalues I simply imagine this graph:

lvalues and xvalues are both glvalues, while xvalues and prvalues are both rvalues. That's really all you need to know in practice.

Maybe a mnemonic to remember lvaluse, xvalues, and prvalues go at the bottom are the words Lower eXPRessions (it contains L, X, and PR). Maybe not.

OTHER TIPS

You usually only need to know whether something is an lvalue or an rvalue. These two categories of expressions are distinct from one another.

It is usually the case that an lvalue expression refers to something that is going to hang around for a while. For example, a variable name is an lvalue because variables stick around. On the other hand, rvalue expressions usually refer to something that is only existing temporarily. You can only take the address of an lvalue because why on earth would you need the address of something that was going to disappear soon?

Now, when making this distinction, you have to take into account what the compiler knows at the time. For example, take the function void foo(const A& a). Inside this function, the compiler doesn't know if the object passed was a temporary object or not, so it just assumes that it will stick around. That is, a is an lvalue. Even though you can happily pass a temporary object into this function (call it with an rvalue expression), the expression a is still an lvalue.

Taking this into account, you can further remember whether something is an lvalue or an rvalue by whether it is named. In the above example, since the object gets named as a, it is an lvalue.

Now, for the rest of the categories, you should remember the following diagram:

Diagram of expression categories

Note that lvalues and rvalues are indeed distinct. However, rvalues are split up into two other categories, xvalues and prvalues. Also, xvalues are also considered to be glvalues along with all the lvalue expressions.

Now knowing when these show up comes down to remembering a few cases.

xvalues are not very common. They only show up in situations involving conversions to rvalue references. Here are all of the cases:

  • result of a function that returns an rvalue reference
  • a cast to an rvalue refernece
  • object.x if object is an xvalue
  • object.*member if pobject is an xvalue

By definition, prvalues are every other type of rvalue that is not an xvalue. For example, returning an object by value from a function creates a temporary returned object. The expression denoting that object is a prvalue.

The category glvalue is used to refer to everything that is not an prvalue.

An lvalue can be thought of as a "named" variable or memory location ... an rvalue can be thought of as an "unamed" memory location (i.e., a temporary variable returned from a function) or a pure "value" (i.e., like a number).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top