const引用是否绑定到另一个引用,该引用是从临时的悬空引用转换而来的?

big*_*iao 10 c++ object-lifetime language-lawyer reference-binding

以下是代码段:

#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;
}
Run Code Online (Sandbox Code Playgroud)

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

destruct B
destruct B
1
Run Code Online (Sandbox Code Playgroud)

因此返回值似乎比cout操作早破坏.所以这instance似乎是一个悬垂的参考.

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

destruct B
1
destruct B
Run Code Online (Sandbox Code Playgroud)

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

xsk*_*xzr 8

根据最新的草案[class.temporary]/6(不相关的部分被我删除):

第三个上下文是将引用绑定到临时对象.如果绑定引用的glvalue是通过以下之一获得的,则引用绑定到的临时对象或作为绑定引用的子对象的完整对象的临时对象将持续参考的生命周期:

  • ...

  • 一个const_cast([expr.const.cast]),static_cast([expr.static.cast]),dynamic_cast([expr.dynamic.cast])或reinterpret_cast([expr.reinterpret.cast])转换,没有用户-defined conversion,一个glvalue操作数,它是glvalue的这些表达式之一,引用操作数指定的对象,或者它的完整对象或其子对象,

  • ...

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

const int& x = (const int&)1;  // temporary for value 1 has same lifetime as x
Run Code Online (Sandbox Code Playgroud)

- 结束例子] - 结束说明]

您的代码格式正确.


在C++ 14之前,标准中的措辞不清楚这种情况,并且存在缺陷问题1376.这个问题澄清了临时对象的生命周期应该不会在这种情况下进行扩展.但是,这一澄清被第1299号问题所取代(其解决方案甚至不包括在C++ 17中,而是在当前的草案中).

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

  • @bigxiao没有延长.因为[class.temporary]/6中没有规则适用. (2认同)