我已经习惯了这样一个事实:const引用会延长临时引用的生存期,直到引用超出范围:
class X {};
{
X const & x = X();
// Lifetime of x extended to the end of the scope
// in which x is declared because it was declared
// as a *const* reference
}
我也知道临时一直存在到创建它的表达式结束:
// Contrived example to make a point about lifetime of a temporary in an expression
class Y
{
public:
Y() : y(5) {}
Y & operator+=(int const & rhs)
{
y += rhs;
return *this;
}
int foo() { return y; }
private:
int y;
};
// n in the following line of code is 11 and the code is valid
// - the lifetime of the temporary persists to the end of the expression
int n = (Y() += 6).foo();
假设我对以上两项都是正确的,我怀疑在函数参数列表中创建的临时参数确实会在函数调用的整个生命周期内持续存在,即使它绑定到非常量引用:
class X {};
void foo(X & x)
{
// x is valid in this function,
// even though the parameter is declared
// as a *non*-const reference - correct?
}
// Valid, I think, even though the function parameter
// is declared as a **non**-const reference
// - because the lifetime of the temporary persists until the expression
// is fully evaluated - right?
foo(X());
我认为我的经验和理解是正确的——将函数参数列表中创建的临时绑定到non-const引用参数是安全的。
但我想确认我是对的,因为我在任何地方都找不到这个问题的答案。
谢谢!
当然你是对的。
标准:
12.2临时物体[临时类]
[…]
在两种上下文中,临时性在与完整表达式结尾不同的位置被销毁
第一个上下文是当调用默认构造函数来初始化数组的元素时。如果构造函数有一个或多个默认参数,即销毁在默认值中创建的每个临时参数参数在构造下一个数组元素(如果有的话)之前进行排序
第二个上下文是引用绑定到临时的。引用绑定到的临时对象或作为引用绑定到子对象的完整对象的临时对象在引用的生存期内持续存在,但以下情况除外:
--构造函数的ctor初始值设定项(12.6.2)中与引用成员的临时绑定将持续存在,直到构造函数退出
--函数调用(5.2.2)中引用参数的临时绑定将持续存在,直到包含该调用的完整表达式完成为止
--函数返回语句(6.6.3)中返回值的临时绑定的生存期不会延长;临时在return语句中的完整表达式末尾被销毁
--到新初始值设定项(5.3.4)中引用的临时绑定将持续存在,直到完成包含新初始值设定项的完整表达式。
想使用另一个级别的构造函数和存储引用的对象再次提出这个问题吗?
重复数据删除程序已经给出了语言律师的答案,下面是实现细节的答案:
如果通过引用传递任何对象,则实际上是在传递指向该对象的指针。由于调用者只传递指向对象的指针,因此通过引用传递的对象必须由调用者构造。
另一方面,被调用者只看到传入的指针。它看不到调用者是如何构造其指针的对象的。此对象可以是临时的(仅在const
引用的情况下,因为临时不能作为非常量引用传递),也可以是具有函数范围的变量,它可以是其调用者已经传递给调用者的对象,甚至可以是分配了new
的对象。因此,它无法销毁对象,因为它不知道如何销毁。
因此,在被调用者将控制权返回给调用者之后,由调用者清理临时——通过引用传递的任何内容都必须在被调用者的整个运行时内有效。
请注意,关于引用是否为const
,整个论点是完全未知的。