OneRaynyDay / oneraynyday.github.io

Other
9 stars 7 forks source link

dev/2020/07/03/Value-Categories/ #11

Open utterances-bot opened 2 years ago

utterances-bot commented 2 years ago

The Story of Value Categories in C++ | Ray

When you see the C++ standard’s specification on value categories, it’s likely your eyes gloss over and you think to yourself - “why do I ever need to know this?”. At least that’s what I thought when I first took a glance. Over the years, I’ve ran into issues assuming a simplistic model of value categories, and I regret not taking a long hard look at the standard in the beginning. This is my attempt to explain value categories in a fun history lesson (at the time of writing, this view is representative of up to C++20).

http://oneraynyday.github.io/dev/2020/07/03/Value-Categories/

IvonLiu commented 2 years ago

Thanks Ray! This is so helpful!

Nnarol commented 1 year ago

Nice concise picture, but I have found sources on the internet which contradict some of the statements.

Recall that before C++11, we have the notions of lvalues and rvalues which are further divided into xvalues and prvalues. The reason rvalues were split into the two was because it could be temporarily materialized into an expiring value using const references.

So from this, I gather that as of C++ 11, prvalues, i.e. values returned by value from functions, or results of constructor calls are "materialized" into temporaries , which are in turn xvalues, whenever they need to be bound to an lvalue such as a variable or a const reference parameter.

However, the accepted answer of Nicol Bolas in this StackOverflow question: https://stackoverflow.com/questions/38043319/how-does-guaranteed-copy-elision-work

says:

Pre-C++17, prvalues are temporary objects. In C++17, a prvalue expression is merely something which can materialize a temporary, but it isn't a temporary yet.

So according to this, prvalues - rather than xvalues -, are the temporaries themselves, they do not materialize into them.Tthey do so only starting with C++ 17.

Which is correct then?

OneRaynyDay commented 1 year ago

Yeah good catch! In C++11 the only difference between xvalues and prvalues is in the distinction of identity, which is also a lawyer term that essentially means whether two equivalent expressions in the same value category can be discernible from each other (You can't really tell the difference between two calls of Foo() prvalues, but you can tell between std::move(foo1) and std::move(foo2) simply by their storage):

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

Therefore, the distinction about whether a prvalue is really a temporary object isn't clearly defined by the standard, but by reading that particular line I would think that if rvalues have temporary storage then you can simply discern between them by checking their addresses. (In my interpretation, being a temporary implies having temporary storage, I might be wrong!)

In reality though, IIRC even since early 2010's prvalues have been treated by compilers like they've been in 2017 - guaranteed RVO has been implemented prior to std=c++17 by gcc, clang, mvsc etc, so in order for that to be true they must've implicitly decided prvalues are not temporaries.