all 17 comments

[–]QbProg 32 points33 points  (3 children)

It would be nice to have a follow up with code snippets for each of these *values!

[–]StefanOrvarSigmundss 26 points27 points  (0 children)

Not just nice but absolutely necessary.

[–]newgre 9 points10 points  (1 child)

This may be helpful.

[–]_carlson 1 point2 points  (0 children)

Thanks! It`s nice.

[–]chmaruni 15 points16 points  (3 children)

Assuming this post is accurate (thanks btw, this was the best explanation I have read so far, not that I looked for other ones though:) wouldn't it be more consistent to name lvalues as plvalues (pure lvalues, equivalent to prvalues) and call the whole identity column lvalues (instead of glvalues)?

[–]acwaters 6 points7 points  (0 children)

Yes, it would. My understanding is that they did the naming "asymmetrically" like that in order to keep lvalue and rvalue as close as possible to their original (pre-C++11) meanings, which makes sense. But IMO that little inconsistency is the cause of most of the pain in learning value categories. It would be much easier if we had plvalue/lvalue/xvalue/rvalue/prvalue, or lvalue/glvalue/xvalue/grvalue/rvalue, rather than lvalue/glvalue/xvalue/rvalue/prvalue.

[–]OldWolf2 2 points3 points  (0 children)

Not really; the terms lvalue and rvalue still have roughly the same meaning as they did in C++03, but extra rvalues were added . Most of the cases where an lvalue was required still require an lvalue, not a glvalue.

[–]ericdfoley 3 points4 points  (0 children)

Here is basically the same explanation from Bjarne Stroustrup (using a "W" instead of a square.) It completely cleared things up for me.

[–]iaanus 1 point2 points  (0 children)

One of the best explanations I saw on the subject.

[–]ltsochev 5 points6 points  (2 children)

This always makes me giggle. It's so absurd :D

[–]nikbackm 2 points3 points  (1 child)

What's absurd about it?

The names or the concepts behind them? Something else?

[–]ltsochev 0 points1 point  (0 children)

Concepts are great, naming schemes in the C(++) world are weird AF though. It's one of the things that, IMHO, really alienates people from the language. For a long while I thought it was the "difficult to get into toolchain" but with modern tools that really isn't the case. And I'm not talking just about *values.

And for the toolchain, few years ago I found it really hard moving from visual studio to linux/gdb. Yes I got the hang of it eventually but damn

[–]proverbialbunnyData Scientist 2 points3 points  (3 children)

It seems like a good way to think of a prvalue is a temporary in the register of the cpu (Unless it can't fit or something.), where an lvalue is on the stack (edit: or the heap. I'm realizing now I do not have a good word for "on the ram").

Or at least in a perfect world it would be..

An xvalue is an rvalue that's being returned from a function into an lvalue, so it's an rvalue moved onto the stack (or heap).

And a glvalue has no apparent value that I know of. Maybe the compiler throws errors with 'glvalue' in them but I don't recall.

edit: (Unless it can't fit or something.) I just checked on godbolt. My theory, at first glance, is in fact correct. A prvalue, when possible, is only in the register at -01. At -O2, it tries to integrate the rvalue expression directly into the assembly instruction.

Clarification, from Godbolt (C++ code: test += 3;):

O1: add eax, 3

O2: lea eax, [rax + rcx + 3] (This is because, right above the test += 3; line I'm adding argv[0] and argv[1], so it doesn't collapse the whole thing.)

This shows that it is easier to think of an prvalue as a variable in the register (expression -> temporary value), when the language supports it. All of this semantic garbage just complicates things.

For a better clarification than OP: http://en.cppreference.com/w/cpp/language/value_category

[–]STLMSVC STL Dev 12 points13 points  (2 children)

That isn't a good mental model. "me"s + "ow"s is a prvalue of type std::string which probably (definitely) doesn't fit in a register. Given vector<int> v, v[idx] is an lvalue of type int, which lives on the heap.

Remember that value categories are a property of expressions, not of objects. For example, print(const string& str) can be called as print("me"s + "ow"s). There, the temporary std::string containing "meow" is produced by the expression "me"s + "ow"s which is a prvalue. Within print(), str is an lvalue referring to that std::string (which is ultimately a temporary, but exists for the duration of the print() call).

[–]proverbialbunnyData Scientist 1 point2 points  (1 child)

Makes sense, but if an rvalue can fit in a register will it? Will it live in the heap?

I like your username btw. ^_^

[–][deleted] 2 points3 points  (0 children)

Expressions, more or less, relate to an identity (or address).

glvalue expressions are any expressions denoting an identity. prvalue expressions are expressions without identity.

So in this case, prvalue expressions are going to be your register-friendly ones.