开发者

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 temporar开发者_Python百科ies 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?


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.


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.


double& d = 3 + 4; is not fully legal, in fact it won't be accepted by a standard-compliant compiler. The result of 3+4 is a temporary of type int - as such it can only be bound to a const reference.

Binding references is really binding. There is no copying involved. It's simply extending the lifetime of a temporary object.


void f( int & n ) {
}

int main() {
    f( 1 + 2 );
}

No copy construction involved, but the temporary will not be bound. Error with g++ is:

invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'


Reference can be initialized by lvalue of same type and 3 + 4 is not lvalue. So this is not legal. MS VC++ compiler permits doing something similar to your objects, but this is not in standard.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜