Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the deal with temporary objects and references?

One can frequently read that you cannot bind normal lvalue reference to temporary object. Because of that one can frequently see methods of class A taking const A& as a parameter when they don't want to involve copying. However such construct is fully legal:

double& d = 3 + 4;

because it doesn't bind temporary object 3 + 4 to reference d, but rather initializes reference with an object 3 + 4. As standard says, only if value is not of type or the reference (or inherited), reference won't be initialized using object obtained from temporary object using conversion or sth (i.e. another temporary object). You can see that in this case:

int i = 2;
double & d = i;

That's not legal, because i is not of type double, nor it inherits from it. However that means, that temporaries can be bound to references - but is it really binding? Isn't it rather creating a new object using copy constructor with temporary object as its parameter?

Therefore, as I think, point of having methods taking const A& param instead of A& is not that in second case such method won't be able to take as parameter temporary object of type A (because it will), but because it involves copy constructor (just as if the parameter would be of type A). Am I right?

like image 858
Argbart Avatar asked Dec 10 '22 09:12

Argbart


2 Answers

First, as others have said, double& d = 3 + 4; is not legal C++; if your compiler accepts it, and claims to be compiling C++, it's an error in the compiler. (Note that most C++ compilers do not claim to compile C++ unless you give them special options, -std=c++98 in the case of g++, for example.)

Secondly, the motivation for this rule comes from experience. Consider the following example:

void
incr( int& i )
{
    ++ i;
}

unsigned x = 2;
incr( x );  //  Implicit conversion of unsigned to int
            //  creates a temporary.
std::cout << x << std::endl;
            //  and x is still equal 2 here.

The original implementation of references did not have this restriction; you could initialize any reference with a temporary. Actual experience showed this to be too error prone, so the restriction requiring a reference to const was introduced. (Around 1988 or 1989, so there's no excuse today for a compiler to not enforce it.)

Note too that one often hears that binding a temporary to a const reference extends the temporary's lifetime. This is very misleading: using a temporary to initialize a reference extends the temporary's lifetime (with certain exceptions), but the lifetime is not extended if this reference is used to initialize other references, even though the temporary is also bound to those references.

like image 81
James Kanze Avatar answered Dec 26 '22 00:12

James Kanze


If you worry about the meaning and purpose of const & vs. & in function parameter lists, I fear you are barking up the wrong tree, as it has little to do with temporary objects.

void method( Object x );

This does copy-construct an Object from the actual argument. Any changes done to x within the function are lost when the function terminates, the argument to the function is not changed.

But you don't want to pay the cost of copy-construction.

void method( Object & x );

This does not copy-construct an Object from the actual argument, but x refers to the argument, i.e. any changes done to x within the function are really done to the argument itself.

But you don't want to have callers of the method wondering about what might happen to their arguments.

void method( const Object & x );

This does not copy-construct an Object from the actual argument, and x cannot be changed within the function.

You don't pay for the copy-constructor, and you make it clear to the caller that his argument won't be tampered with.

You cannot pass a temporary object as argument to the second variant (see unapersson's answer), because there would be no changeable object to refer to, but as that function heralds loudly that it will be modifying the argument (as it's declared a non-const reference), passing a temporary as argument is non-sensical anyway.

like image 38
DevSolar Avatar answered Dec 25 '22 22:12

DevSolar