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 类型的临时对象(因为它会),而是因为它涉及复制构造函数(就像参数是 A 类型一样)。我对吗?

4

5 回答 5

7

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

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

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 引用会延长临时对象的生命周期。这是非常具有误导性的:使用临时对象来初始化引用会延长临时对象的生命周期(有某些例外),但如果此引用用于初始化其他引用,则生命周期不会延长,即使临时对象也绑定到这些引用。

于 2011-05-05T13:24:11.110 回答
6

如果您担心函数参数列表中const &vs.的含义和目的&,我担心您会找错树,因为它与临时对象关系不大。

void method( Object x );

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

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

void method( Object & x );

这不会Object实际参数复制构造 an ,但 x的是参数,即对函数内所做的任何更改x实际上都是对参数本身进行的。

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

void method( const Object & x );

这不会Object实际参数复制构造一个,并且x不能在函数内更改

您无需为复制构造函数付费,并且向调用者明确说明他的论点不会被篡改。

您不能将临时对象作为参数传递给第二个变体(请参阅 unapersson 的答案),因为没有可更改的对象可以引用,但是因为该函数大声预示它将修改参数(因为它被声明为非常量参考),无论如何传递一个临时参数是没有意义的。

于 2011-05-05T09:53:24.290 回答
1

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

绑定引用确实具有约束力。不涉及复制。它只是延长临时对象的生命周期。

于 2011-05-05T09:50:40.767 回答
0

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

于 2011-05-05T10:57:47.520 回答
0
void f( int & n ) {
}

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

不涉及复制构建,但临时不会绑定。g++ 的错误是:

从“int”类型的右值初始化“int&”类型的非常量引用无效

于 2011-05-05T09:50:13.770 回答