Why does temporary object get created here?
Asked Answered
R

2

5
class X{
public:
    X(){}
};

class Y{
public:
    Y(X x) { std::cout << "Temporary created!"; }
};

int main(){
    X x;
    const Y& y = x;
    return 0;
}

Why does temporary object (of type Y) get created here? I understand the necessity of a temporary object in this case, but I don't understand what the standard says about it. If we take a look at the standard, the only case which would fit our case here would be binding a reference to a prvalue, if I'm not mistaken. So does the subexpression x in const Y& y = x get converted to a prvalue or something else is happening here?

I've also taken a look at lvalue -> rvalue conversion, but the whole thing seems poorly explained. It doesn't say anything about the scenarios in which would this type of conversion occur. As far as I can tell, this conversion happens more often than I thought. For example, if we would take a look at implicit conversions on cpp.reference, almost every section starts with "A prvalue of an XXX type can be converted to YYY..." which indicates that most of the time in implicit conversions we use the lvalue->rvalue conversion as some kind of a base conversion. Closely related, I've also taken a look at this topic which could be a nice take on the whole situation, but also could be rather outdated.

So basically, I've got two questions. The first one from the title and (possibly not related) the second one: When does lvalue -> rvalue conversion actually occur ?

EDIT: regarding my first question (from the title) I've developed a theory which I believe fits with the draft. Basically, the expression x gets converted to a prvalue of type const Y, but without creating any objects. After that, we have a binding to prvalue which induces temporary materialization converting prvalue to xvalue. Only then we're binding a const reference to that temporary object. How far am I from the truth?

Reber answered 4/4, 2022 at 15:45 Comment(3)
Ask yourself: Which Y object does y refer to when I do const Y& y = x;? x is not a Y, so y cannot be referring to it.Hanky
If we take a look at the standard … So does the subexpression x in const Y& y = x gets converted to a prvalue or something else is happening here? Have you followed the links from "the standard"? (e.g. eel.is/c++draft/dcl.init.ref)Drumstick
@Hanky I understand why the temporary is needed as I mentioned. I'm interested in the standard's point of view.Reber
I
3

I believe x is being implicitly converted to a Y object.

Implicit Conversion

An expression e is said to be implicitly convertible to T2 if and only if T2 can be copy-initialized from e, that is the declaration T2 t = e; is well-formed (can be compiled), for some invented temporary t.

Y can be copy-initialized from X, Y(X x) { ... } constructor is called.


r-values can bind to const l-value reference. Hence, const Y& y = x; is valid.

Infuse answered 4/4, 2022 at 15:56 Comment(0)
B
3

Why does temporary object gets created here?

The constructor Y::Y(X x) that you provided is called a converting constructor. By providing this constructor, you're basically saying that an object of type X can be used where an object of type Y is expected.

Now, lets see what's happening in your case. When you wrote:

const Y& y = x;

In the above statement, y is an lvalue reference to const Y. This means that y is expecting to be bound to a Y type object. But you provided object x which is of type X. So there will be an implicit conversion of x to a Y prvalue, which will be done using the converting constructor. This is why it is called a converting constructor in the first place .

But note that const Y& expects a glvalue and we currently have a prvalue on the right hand side. Thus, the temporary materialization rule kicks in and the prvalue expression is converted to an xvalue. Now since an lvalue reference to const Y is allowed to bind to an xvalue(since an xvalue is also a glvalue), y is successfully bound to this materialized xvalue.

Bridwell answered 5/4, 2022 at 17:47 Comment(7)
Doesn't xvalues represent temporary objects? Prvalues would represent a pure value. The way I get it is that x gets converted to a prvalue of type const Y (glvalue X -> prvalue const Y conversion) after which it gets converted to an xvalue of type Y denoting the temporary object. Only then we actually get reference binding of y to that temporary object. Source of my reasoning: draft. What do you think, do you agree with my reasoning?Reber
@Reber Yes temporary materialization will happen here and y will be bound to the materialized xvalue. I have updated the answer accordingly. Check out the updated answer.Bridwell
I think temporary is being created at the moment of prvalue -> xvalue conversion. My take is that we first have a conversion to const Y prvalue without any temporaries being created and after that we have prvalue -> xvalue conversion which induces temporary materialization. I don't know if I'm correct though.Reber
You're mentioned temporary object twice if I'm not mistaken in two separate occasions. Did you mean that we have two temporaries created or are you referring to the same temporary object? Also I don't understand the "temporary Y object (a prvalue)" part. Maybe you meant xvalue instead?Reber
@Reber Yes, only one temporary object will be involved here(to my current understanding) which will be materialized when the "temporary materialization rule" kicks in. I forgot to remove term "temporary object" when i last edited my answer while talking about prvalue. This time(in my edited answer) i have removed that term when talking about prvalue.Bridwell
I've still got some questions, do you maybe want to continue this discussion privately?Reber
Let us continue this discussion in chat.Reber

© 2022 - 2024 — McMap. All rights reserved.