2

关于 SO 上的常量引用的生命周期有几个问题,但我仍然不明白。

这段代码有效吗?

struct S
{
    const int &ref;
    S( const int &x ) : ref(x) { }
};

int main( )
{
    S s( 0 );
    // ...
    use( s.ref );
    // ...
    return 0;
}

直觉上我会说不,因为应该在计算表达式 ( )0之后过期。S s(0);

但是 GCC 和 CLANG 都可以很好地编译它,没有警告,并且 valgrind 没有检测到任何运行时错误。

我在参考中缺少什么?

4

5 回答 5

4

根据 12.2/4 对我来说似乎无效:

在两种情况下,临时对象在与完整表达式结束时不同的点被销毁。第一个上下文是 当表达式作为定义对象的声明符的初始值设定项出现时在这种情况下,保存表达式结果的临时变量将持续存在,直到对象的初始化完成

临时对象只能在s完全构建之前存在,直到use被调用为止。

于 2010-12-23T22:29:12.013 回答
2

正如其他人指出的那样,C++ 标准仅强制编译器在0调用构造函数的持续时间内保留临时变量。在实践中,gcc 在main函数执行期间保持临时状态,从而导致程序按预期运行。因此,没有警告或运行时错误。

但这只是偶然的。不要依赖这种行为。

于 2010-12-23T23:02:29.500 回答
1

这里要注意的不是const参考而是参考。const 只是静态分析的工具。您需要小心参考,因为它们会咬人。

int& f()
{
    int i = 2;
    return i;
}

有时编译器足够聪明,可以警告您运行时会出现的问题,但有时不会。无论哪种方式,编译器都不必就此发出警告。

于 2010-12-23T22:38:09.193 回答
1

这是对您的代码的另一个调整,甚至 valgrind 都抱怨:

#include <iostream>

struct S
{
    const int &ref;
    S( const int &x ) : ref(x) { }
};

S* foo()
{
    return new S(0);
}

int main( )
{
    S* s = foo();
    std::cout << s->ref << std::endl;
    return 0;
}

这通常将临时文件放在函数的堆栈帧中foo,因此当该函数返回时它会被销毁。这类似于返回局部变量的地址。

其他答案指出了为什么允许编译器这样做,我的代码只是一个说明。

于 2010-12-23T23:28:55.583 回答
0

0不是临时的,是字面的。尝试对您的程序进行这个小改动:

struct S 
{
    const int &ref;
    S( const int &x ) : ref(x) { }
};

int f()
{
    return 0;
}

int main( )
{
    S s( f() );
    // ...
    use( s.ref );
    // ...
    return 0;
}

我认为引用临时的规则只适用于局部变量,而不是成员。

于 2010-12-23T22:29:51.280 回答