简体   繁体   English

临时对象和引用是怎么回事?

[英]What's the deal with temporary objects and references?

One can frequently read that you cannot bind normal lvalue reference to temporary object.可以经常读到您无法将正常的左值引用绑定到临时 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.因此,当不想涉及复制时,经常可以看到 class A 将 const A& 作为参数的方法。 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 (ie another temporary object).因为它不会将临时 object 3 + 4 绑定到引用 d,而是使用 object 3 + 4 初始化引用。正如标准所说,只有当值不是类型或引用(或继承)时,引用才会使用从临时 object 获得的 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.这是不合法的,因为 i 不是 double 类型,也不是从它继承的。 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?难道不是使用临时 object 作为参数的复制构造函数创建一个新的 object 吗?

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).因此,正如我认为的那样,让方法采用 const A& param 而不是 A& 的意义在于,在第二种情况下,这种方法不能将 A 类型的临时 object 作为参数(因为它会),而是因为它涉及复制构造函数(就像参数是 A 类型一样)。 Am I right?我对吗?

First, as others have said, double& d = 3 + 4;首先,正如其他人所说,double& d = 3 + 4; is not legal C++;合法 C++; if your compiler accepts it, and claims to be compiling C++, it's an error in the compiler.如果您的编译器接受它,并声称正在编译 C++,那么这是编译器中的错误。 (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.) (请注意,大多数 C++ 编译器并不声称可以编译 C++,除非您给它们提供特殊选项,例如-std=c++98在 g++ 的情况下。)

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.实际经验表明这太容易出错,因此引入了需要引用 const 的限制。 (Around 1988 or 1989, so there's no excuse today for a compiler to not enforce it.) (大约在 1988 年或 1989 年,所以今天编译器没有理由不强制执行它。)

Note too that one often hears that binding a temporary to a const reference extends the temporary's lifetime.还要注意,人们经常听说将临时对象绑定到 const 引用会延长临时对象的生命周期。 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.如果您担心 function 参数列表中的const &&的含义和目的,我担心您会找错树,因为它与临时对象关系不大。

void method( Object x );

This does copy-construct an Object from the actual argument.这确实从实际参数中复制构造了Object Any changes done to x within the function are lost when the function terminates, the argument to the function is not changed.当 function 终止时,对 function 中的x所做的任何更改都将丢失,function 的参数不会更改。

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, ie any changes done to x within the function are really done to the argument itself.不会从实际参数复制构造Object ,但 x的是参数,即在 function 中对x所做的任何更改实际上都是对参数本身进行的。

But you don't want to have callers of the method wondering about what might happen to their arguments.但是您不希望该方法的调用者想知道他们的 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 .不会从实际参数复制构造Object并且x不能在 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. 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参考),无论如何传递一个临时参数是没有意义的。

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. 3+4的结果是int类型的临时结果 - 因此它只能绑定到 const 引用。

Binding references is really binding.绑定引用确实具有约束力。 There is no copying involved.不涉及复制。 It's simply extending the lifetime of a temporary object.它只是延长临时 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: g++ 的错误是:

invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'从“int”类型的右值初始化“int&”类型的非常量引用无效

Reference can be initialized by lvalue of same type and 3 + 4 is not lvalue.引用可以由相同类型的左值初始化,并且 3 + 4 不是左值。 So this is not legal.所以这是不合法的。 MS VC++ compiler permits doing something similar to your objects, but this is not in standard. MS VC++ 编译器允许执行与您的对象类似的操作,但这不是标准的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM