临时对象和引用是什么意思?

4
人们经常会看到这样的说法:不能将普通左值引用绑定到临时对象上。因此,当类A的方法不想涉及复制时,人们经常会看到使用const A&作为参数。但是,这样的构造是完全合法的。
double& d = 3 + 4;

因为它没有将临时对象3+4绑定到引用d上,而是使用对象3+4初始化了引用。根据标准规定,只有当值不是类型或引用(或继承)的情况下,引用才不会使用从临时对象转换或其他方式获得的对象来初始化(即另一个临时对象)。您可以在此示例中看到:

int i = 2;
double & d = i;

这是不合法的,因为i既不是double类型,也没有继承它。然而,这意味着临时对象可以绑定到引用上 - 但这真的是绑定吗?难道不是使用临时对象作为其参数使用复制构造函数创建新对象吗?

因此,我认为使用const A& param作为方法参数的重点并不在于第二种情况下这样的方法无法将A类型的临时对象作为参数(因为它可以),而是因为它涉及到复制构造函数(就像参数是A类型一样)。我对吗?


3
double& d = 3 + 4; 不合法,因为引用类型未被const限定。 - CB Bailey
只有 double&& d = 3 + 4; 是合法的(在 C++0x 中),因为 3+4 是一个右值(无论它是否有意义,合法与否是另一个问题)。 - Damon
1
很难确定你的问题是什么... - DevSolar
5个回答

7
首先,正如其他人所说的那样, double& d = 3 + 4; 不是合法的C++代码;如果你的编译器接受它,并且声称在编译C++代码,那么这是编译器中的错误。(请注意,大多数C++编译器除非你使用特殊选项,例如g++中的-std=c++98,否则不会声称编译C++代码。)
其次,这个规则的动机来自经验。考虑以下例子:
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引用会延长临时变量的生命周期。这非常误导人:使用临时变量初始化引用会延长临时变量的生命周期(有一定的例外),但如果该引用用于初始化其他引用,则不会延长生命周期,即使临时变量也绑定到这些引用。


6
如果你担心函数参数列表中 const && 的含义和目的,那么恐怕你正在走错方向,因为这与临时对象无关。
void method( Object x );

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

但是,您不想支付复制构造的成本。

void method( Object & x );

这不是从实际参数拷贝构造一个Object,而是x引用该参数,也就是函数内对x所做的任何更改都会真正地作用于该参数本身。

但是您不希望方法的调用者担心他们的参数可能会发生什么。

void method( const Object & x );

这不是从实际参数复制构造一个Object,且x在函数内部无法更改

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

您不能将临时对象作为第二个变量的参数传递(请参见unapersson的答案),因为没有可更改的对象可以引用,但由于该函数大声宣称它将修改参数(因为它声明为非const引用),因此将临时对象作为参数传递是毫无意义的。


1

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

绑定引用确实是绑定。没有涉及复制。它只是扩展了临时对象的生命周期。


0

引用可以通过相同类型的左值进行初始化,而3 + 4不是左值。因此这是不合法的。MS VC++编译器允许对您的对象进行类似的操作,但这不符合标准。


0
void f( int & n ) {
}

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

没有涉及复制构造,但是临时对象将不会被绑定。使用g++出现错误:

无效的非const 引用初始化类型' int&' ,来自类型'int' 的rvalue


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接