domdrag
domdrag

Reputation: 601

Why does temporary object get created here?

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?

Upvotes: 5

Views: 767

Answers (2)

user12002570
user12002570

Reputation: 1

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.

Upvotes: 3

TheScore
TheScore

Reputation: 330

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.

Upvotes: 3

Related Questions