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

What's the deal with temporary objects and references?

本文关键字:怎么回事 引用 临时对象      更新时间:2023-10-16

人们经常会读到,不能将正常的左值引用绑定到临时对象。正因为如此,我们经常可以看到类A的方法采用常量A&作为一个参数,当他们不想涉及复制时。然而,这种结构是完全合法的:

double& d = 3 + 4;

因为它没有将临时对象3+4绑定到引用d,而是使用对象3+4初始化引用。正如标准所说,只有当值不是类型或引用(或继承的(时,引用才不会使用从使用转换或sth的临时对象(即另一个临时对象(获得的对象进行初始化。你可以在这种情况下看到:

int i = 2;
double & d = i;

这是不合法的,因为i不是double类型,也不是从中继承的。然而,这意味着临时变量可以绑定到引用,但它真的有约束力吗?它不是更倾向于使用以临时对象为参数的复制构造函数来创建一个新对象吗?

所以,正如我所认为的,有方法取常量A&param而不是A&并不是说在第二种情况下,这种方法不能将A类型的临时对象作为参数(因为它会(,而是因为它涉及复制构造函数(就像参数是A类型一样(。我说得对吗?

首先,正如其他人所说,双&d=3+4;是不是合法C++;如果您的编译器接受它,并声称正在编译C++,这是编译器中的一个错误。(注意大多数C++编译器并不声称编译C++,除非您给出它们是特殊选项,在g++的情况下为-std=c++98例如。(

其次,这条规则的动机来自于经验。考虑以下示例:

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.

参考文献的原始实现没有限制规定可以使用初始化任何引用短暂的实际经验表明这太容易出错,因此,需要引用const的限制是介绍。(大约在1988年或1989年,所以今天没有任何借口让编译器不强制执行。(

还要注意的是,人们经常听说将临时绑定到const引用延长了临时的生存期。这是非常误导:使用临时来初始化引用扩展临时人员的生存期(某些例外(,但如果此引用用于初始化,则寿命不会延长其他引用,即使临时引用也绑定到这些参考文献。

如果您担心函数参数列表中const &&的含义和用途,我担心您会弄错树,因为它与临时对象几乎没有关系。

void method( Object x );

这确实从实际参数中复制构造了一个Object。函数终止时,对函数内x所做的任何更改都将丢失,函数的参数不会更改。

但你不想支付复制构建的成本。

void method( Object & x );

这并不是从实际参数中复制构造Object,而是将x引用到参数中,即函数中对x所做的任何更改实际上都是对参数本身所做的。

但是,您不希望方法的调用方想知道他们的参数可能会发生什么。

void method( const Object & x );

这并不是从实际参数中复制构造Object,并且不能在函数中更改x

你不需要为复制构造函数付费,并且你向调用者明确表示他的参数不会被篡改。

您不能将临时对象作为参数传递给第二个变量(请参阅Unpersson的答案(,因为没有可引用的可变对象,但由于该函数大声宣告它将修改参数(因为它被声明为非常量引用(,因此传递临时对象作为参数无论如何都是没有意义的。

double& d = 3 + 4;不是完全合法的,事实上,它不会被符合标准的编译器所接受。3+4的结果是int类型的临时结果,因此它只能绑定到常量引用。

绑定引用确实具有绑定性。不涉及复制。它只是延长一个临时对象的寿命。

void f( int & n ) {
}
int main() {
    f( 1 + 2 );
}

不涉及复制施工,但临时工程不受约束。g++的错误为:

非常量初始化无效类型为'int&'的引用来自"int"类型的右值

引用可以由相同类型的左值初始化,3+4不是左值。所以这是不合法的。MS VC++编译器允许执行与对象类似的操作,但这不是标准操作。