5

考虑以下处理 const 引用的代码:

const int & func (const int &x)
{
    return x;
}

struct Foo {
    Foo (const int &x)
    : m_x(x) {}

    const int & getX ()
    { return m_x; }

    const int &m_x;
};

我想知道现在允许以下哪些(如果有):

int x = func(int(7));
int y = Foo(int(7)).getX();

是否可以保证临时int对象在分配或使用之前仍然存在getX

更新:所以看起来这是安全的 - 但究竟为什么呢?

  1. 是因为临时对象递归地绑定到 const 引用并且只要对它们的绑定引用存在就保证存在?
  2. 或者是因为它们保证在完整表达式的持续时间内存在?

考虑存储指针而不是引用的边缘情况:

struct Foo {
    Foo (const int &x)
    : m_x(&x) {}

    const int & getX ()
    { return *m_x; }

    const int *m_x;
};

int y = Foo(int(7)).getX();

似乎如果案例 1) 是正确的,这将不起作用。但如果情况 2) 是正确的,它会。

4

2 回答 2

7

两者都是安全的,因为您将值复制到xandy中。临时变量在完整表达式结束之前有效。

12.2 临时对象

4) 有两种情况,其中临时对象在与完整表达式结尾不同的点被销毁。第一个上下文是调用默认构造函数来初始化数组元素时。如果构造函数有一个或多个默认参数,则在默认参数表达式中创建的任何临时变量在从构造函数返回后立即被销毁。

5)第二个上下文是引用绑定到临时的。引用绑定到的临时对象或作为引用绑定到的子对象的完整对象的临时对象将在引用的生命周期内持续存在,除非下面指定。临时绑定到构造函数的 ctor-initializer (12.6.2) 中的引用成员将持续存在,直到构造函数退出。临时绑定到函数调用 (5.2.2) 中的引用参数将一直持续到包含调用的完整表达式完成为止。在函数返回语句 (6.6.3) 中对返回值的临时绑定将持续存在,直到函数退出。在所有这些情况下,在初始化引用的表达式评估期间创建的临时对象,除了引用绑定到的临时对象,在创建它们的完整表达式结束时被销毁,并且以它们构建完成的相反顺序被销毁。如果引用绑定到的两个或多个临时对象的生命周期在同一点结束,则这些临时对象在该点以与它们的构造完成相反的顺序被销毁。此外,绑定到引用的临时对象的销毁应考虑具有静态或自动存储持续时间的对象的销毁顺序(3.7.1,3.7.2);也就是说,如果obj1是在创建临时对象之前创建的具有静态或自动存储持续时间的对象,则临时对象应在obj1被销毁之前被销毁;如果 obj2 是在创建临时对象后创建的具有静态或自动存储持续时间的对象,obj2 销毁后,临时应销毁。[ 例子:

class C 
{ 
/ / ... 
public : 
    C(); 
    C(int ); 
    friend C operator +(const C&, const C&); 
    ~C(); 
}; 
C obj1 ; 
const C& cr = C (16)+ C (23); 
C obj2 ; 

表达式 C(16)+C(23) 创建了三个临时变量。第一个临时 T1 保存表达式 C(16) 的结果,第二个临时 T2 保存表达式 C(23) 的结果,第三个临时 T3 保存这两个表达式相加的结果。然后将临时 T3 绑定到参考 cr。未指定先创建 T1 还是 T2。在 T1 在 T2 之前创建的实现中,可以保证 T2 在 T1 之前被销毁。临时变量 T1 和 T2 绑定到 operator+ 的引用参数;这些临时对象在包含对 operator+ 的调用的完整表达式的末尾被销毁。绑定到引用 cr 的临时 T3 在 cr 的生命周期结束时,即程序结束时被销毁。此外,T3的销毁顺序考虑了其他具有静态存储时长的对象的销毁顺序。即因为obj1在T3之前构造,T3在obj2之前构造,所以保证obj2在T3之前销毁,T3在obj1之前销毁。—结束示例]

于 2012-09-23T11:27:47.273 回答
1

两者都是安全的。临时对象可以绑定到const引用,并且它们会持续到绑定临时对象的表达式被执行。在这种情况下,您将它绑定到构造函数参数,并且它一直存在到构造函数的右大括号。

一个类似的现象是使用临时函数作为const引用的默认函数参数:

void foo(const someclass& bla = someclass()); // bind const ref with default constructed someclass
于 2012-09-23T11:28:49.593 回答