10

下面是代码片段:

#include <iostream>
using namespace std;
struct B{
     int b;
     ~B(){cout <<"destruct B" << endl;}
};
B func(){
    B b;
    b.b = 1;
    return b;
}
int main(){
    const B& instance = (const B&)func(); //is `instance` a dangling reference?
    cout <<instance.b<<endl;
    return 0;
}

这个在线编译器中,输出是

destruct B
destruct B
1

所以返回值似乎比cout操作更早破坏。所以这instance似乎是一个悬而未决的参考。

如果我们更改const B& instance = (const B&)func();const B& instance =func();,那么结果是

destruct B
1
destruct B

作为补充,如果我在vs2015中测试代码,那么输出就是最后一个。但是,如果在gcc(4.6 之前)中测试,输出是前者,但在 4.6 之后的版本中是后者。所以我想知道是在线编译器错误还是引用实际上是悬空的。

4

1 回答 1

8

根据最新草案[class.temporary]/6(我省略了无关部分):

第三个上下文是引用绑定到临时对象时。如果通过以下方式之一获得引用绑定到的泛左值,则引用绑定到的临时对象或作为引用绑定到的子对象的完整对象的临时对象在引用的生命周期内持续存在:

  • ...

  • const_cast ([expr.const.cast])、static_cast ([expr.static.cast])、dynamic_cast ([expr.dynamic.cast]) 或 reinterpret_cast ([expr.reinterpret.cast]) 转换,无需用户-定义的转换,作为这些表达式之一的glvalue操作数到glvalue,glvalue指代操作数指定的对象,或其完整对象或其子对象,

  • ...

... [注意:显式类型转换([expr.type.conv],[expr.cast])被解释为一系列基本类型转换,如上文所述。[ 例子:

const int& x = (const int&)1;  // temporary for value 1 has same lifetime as x

—结束示例] —结束注释]

您的代码格式正确。


在 C++14 之前,标准中的措辞对这种情况并不清楚,并且存在缺陷问题1376。此问题阐明了在这种情况下不应延长临时对象的生命周期。然而,这一澄清被 issue 1299取代(其决议甚至不包括在 C++17 中,但在当前草案中)。

因此可以得出结论,在问题 1299 解决之前,这是 4.6 之后版本的 GCC 的一个错误。还有一个GCC 的错误报告 52202

于 2018-05-26T14:16:53.423 回答