-3

There are countless explanations as to what the differences between glvalues and prvalues are, but they all pretty much boil down to "everything that has a memory address is a glvalue and everything else is a prvalue".

I have read explanations like https://en.cppreference.com/w/cpp/language/value_category but my question is rather more of the conceptual kind:

So I came to the conclusion that glvalue are just prvalues with an address, but is that correct?

After doing further research I found a credible source which comes to a similar conclusion as me:

"L-values oftern refer to locations in memory. A variable such as daysInYear from the preceeding example is actually a handel to a memory location and is an l-value. R-values on the other hand, can be the very content of a memory location. So, all l-values can be r-values, but not all r-values can be l-values."

Sams Teach Yourself C++ EIGHTH EDITION Page 87-88

tempdev nova
  • 211
  • 1
  • 8
  • 4
    This question is being [discussed on meta](https://meta.stackoverflow.com/questions/419350). – cigien Jul 20 '22 at 16:03

3 Answers3

2

Is it correct to think of an glvalue as an prvalue with an address?

First, all value categories describe expressions, that is, instructions to compute something. Or, if you want to think of something concrete, they are fragments of the abstract syntax tree of the program. ASTs don't "have" addresses.

The expressions that happen to allow the address-of operator to be tacked on to the root of their syntax trees also happen to be classified as lvalue expressions (because their evaluation identifies an object and objects are the entities that have addresses).

Evaluations of prvalue expressions, instead, initialize objects. That "result object" itself has an address, but the expression used to initialize it, like 42, does not: its evaluation results in a pure value that is the same exact entity whether you compute it in C++, write on paper, or pronounce it in Japanese.

So, all l-values can be r-values, but not all r-values can be l-values.

That book is about as credible as a random youtube video, but the bit this quote is misinterpreting is actually notable: it's about a set of implicit conversions called value tranformations: if you place an lvalue expression in a position where only rvalues are allowed, the compiler will insert an invisible conversion node in the AST (if type constraints are also satisfied). Just as it will do if you use an int where a double is expected (hopefully it's easier to see how "all ints can be doubles" is a misinterpretation)

Here's the clang ast for the expression n+1.0 where n names an int variable:

`-BinaryOperator 0x5637e2056340 <col:12, col:14> 'double' '+'
  |-ImplicitCastExpr 0x5637e2056328 <col:12> 'double' <IntegralToFloating>
  | `-ImplicitCastExpr 0x5637e2056310 <col:12> 'int' <LValueToRValue>
  |   `-DeclRefExpr 0x5637e20562d0 <col:12> 'int' lvalue ParmVar 0x5637e2056118 'n' 'int'
  `-FloatingLiteral 0x5637e20562f0 <col:14> 'double' 1.000000e+00

The sub-expression n becomes the DeclRefExpr node (int lvalue), but it's used where rvalues are expected, so compiler builds a larger expression (ImplicitCastExpr), that is an int rvalue. It's used where doubles are expected, so it makes an even larger ImplicitCastExpr, that is a double rvalue, and finally operator+'s requirements are satisfied and the compiler can complete the tree attaching the two double rvalues as its operands.

Cubbi
  • 46,567
  • 13
  • 103
  • 169
1

No, but yes.

An lvalue is something you can take the address of. Whether something has a memory address or not, or more specifically whether it is stored in memory or not is up to the compiler.

Taking the address of something forces the compiler to assign it some memory. But if you don't do that the compiler tries to keep the value in registers. Or even optimize it away completely.

On the other hand the compiler might run out of registers and has to store something in memory (spill it to the stack). So rvalues can end up in memory, at least temporarily.

The name "lvalue" comes from the fact that only lvalues can be on the left side of an assignment, meaning you can assign it a new value. rvalues on the other hand are only allowed on the right side. (lvalues can also be on the right side.)

Goswin von Brederlow
  • 11,875
  • 2
  • 24
  • 42
1

I'm going to assume C++17 or newer, since the definitions were different before.

glvalue is just a prvalue with a memory address

No, not at all.

Prvalues are not objects. On the first glance they look like freshly created objects (such as a constructor call, or a function call that returns by value), but they are not.

A prvalue is something that an object can be created from.

The object creation happens implicitly in all cases, except when the prvalue is used to initialize another object or prvalue. Meaning, if you chain several prvalues, such as MyClass x = MyClass(MyClass(MyClass(42)));, you're guaranteed to only have a single object, x.

After any of the assignments written in the code sample have happened, can the value category on the right side of the assignment be deduced later on?

No.

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207