Search code examples
temporary-objectsvalue-categories

Temporary materialization conversion - Confusion about terminology and concepts


Hi stackoverflow community,

I'm a few months into C++ and recently I've been trying to grasp the concepts revolving around the "new" value categories, move semantics, and especially temporary materialization.

First of all, it's not straightforward to me how to interpret the term "temporary materialization conversion". The conversion part is clear to me (prvalue -> xvalue). But how exactly is a "temporary" defined in this context? I used to think that temporaries were unnamed objects that only exist - from a language point of view - until the last step in the evaluation of the expression they were created in. But this conception doesn't seem to match what temporaries actually seem to be in the broader context of temporary materialization, the new value categories, etc.

The lack of clarity about the term "temporary" results in me not being able to tell if a "temporary materialization" is a temporary that gets materialized or a materialization that is temporary. I assume it's the former, but I'm not sure. Also: Is the term temporary only used for class types?

This directly brings me to the next point of confusion: What roles do prvalues and xvalues play regarding temporaries? Suppose I have an rvalue expression that needs to be evaluated in such a way that it has to be converted into an xvalue, e.g. by performing member access. What will exactly happen? Is the the prvalue something that is actually existent (in memory or elsewhere) and is the prvalue already the temporary? Now, the "temporary materialization conversion" described as "A prvalue of any complete type T can be converted to an xvalue of the same type T. This conversion initializes a temporary object of type T from the prvalue by evaluating the prvalue with the temporary object as its result object, and produces an xvalue denoting the temporary object" at cppreference.com (https://en.cppreference.com/w/cpp/language/implicit_conversion) converts the prvalue into an xvalue. This extract makes me think that a prvalue is something that is not existent anywhere in memory or a register up until it gets "materialized" by such conversion. (Also, I'm not sure if a temporary object is the same as a temporary.) So, as far as I understand, this conversion is done by the evaluation of the prvalue expression which has "real" object as a result. This object is then REPRESENTED (= denoted?) by the xvalue expression. What happens in memory? Where has the rvalue been, where is the xvalue now?

My next question is more specific question about a certain part of temporary materialization. In the talk "Understanding value categories in C++" by Kris van Rens on YouTube (https://www.youtube.com/watch?v=liAnuOfc66o&t=3576s) at ~56:30 he shows this slide:

Understanding value categories in C++ by Kris van Rens

Based on what cppreference.com says about temporary materialization numbers 1 and 2 are clear cases (1: member access on a class pravlue, 2: binding a reference to a prvalue (as in the std::string +operator).

I'm not too sure about number 3, though. Cppreference says: "Note that temporary materialization does not occur when initializing an object from a prvalue of the same type (by direct-initialization or copy-initialization): such object is initialized directly from the initializer. This ensures "guaranteed copy elision"." The +operator returns a prvalue. Now, this prvalue of type std::string is used to initialize an auto (which should resolve to std::string as well) variable. This sounds like the case that is discussed in the prior cppreference excerpt. So does temporary materialization really occur here? And what happens to the objects (1 and 2) that were "denoted" by the xvalue expressions in between? When do they get destroyed? And if the +operator is returning an prvalue, does it even "exist" somewhere? And how is the object auto x " initialized directly from the initializer" (the prvalue) if the prvalue is not even a real (materialized?) object?

In the talk "Nothing is better than copy or move - Roger Orr [ACCU 2018]" on YouTube (https://www.youtube.com/watch?v=-dc5vqt2tgA&t=2557s) at ~ 40:00 there is nearly the same example:

Nothing is better than copy or move

This slide even says that temporary materialization occurs when initializing a variable which clearly contradicts the exception from cppference from above. So what's true?

As you can see, I'm pretty confused about this whole topic. For me, it's especially hard to grasp these concepts as I cannot find any clear definitions of various term that are used in a uniform way online. I'd appreciate any help a lot!

Best regards, Ruperrrt

TL;DR: What is a temporary in the temporary materialization conversion context? Does that mean that a temporary gets materialized or that it is materialization that is temporary? Also temporary = temporary object?

In the slides, is 3 (first slide) respectively 1 (second slide) really a point where temporary materialization occurs (conflicts with what cppreference says about initialization from pravlues of the same type)?


Solution

  • 107 views, 6 months and no answer nor comments. Interesting. Here's my take on your question.

    Temporary materialization should mean "temporary that gets materialized".

    The term temporary is not only used for class types.

    Prvalues, loosely speaking, don't exist in memory unlike xvalues. The thing you should care about is the context. Let's say you have defined a structure struct S { int m; };.

    In the expression S x = S();, subexpression S() denotes a prvalue. The compiler with treat it just as if you have written S x{}; (note that I've put curly brackets on purpose because S x(); is actually a declaration of a function). On the other hand in expression like int i = S().m;, subexpression S() is a prvalue that will be converted to xvalue that is, S() will denote something that will exist in the memory.

    Regarding your second question, the thing you need to know about is that with the C++-17, the circumstances in which temporaries are going to be created were brought down to minimum (cppreference describes it very well). However, the expression

    auto x = std::string("Guaca") + std::string("mole").c_str();

    will require two temporary objects to be created before assignment. Firstly, you are doing member access with c_str() method so a temporary std::string will be created. Secondly, the operator + will bind one a reference to the std::string("Guaca") (new temporary). and one to the result object of c_str(), but without creating additional temporary because of:. That's pretty much it. It's worth to note that the order of creation temporary objects isn't known - it totally depends on the compiler.

    After that, we're calling the operator + which probably constructs another std::string which technically isn't a temporary object because that's a part of the implementation. That object might or might not be constructed into the memory location of x depending on the NRVO. In any case, whatever value does the prvalue expression std::string("Guaca") + std::string("mole").c_str() denote will be the same value (of the same object) denoted by the expression x because of cpp.ref:

    Note that temporary materialization does not occur when initializing an object from a prvalue of the same type (by direct-initialization or copy-initialization): such object is initialized directly from the initializer. This ensures "guaranteed copy elision".

    This quote isn't really precise and might confuse you so I also suggest reading copy elision (the first part about mandatory elision).

    I'm not a C++ expert so take all of this with a grain of salt.