【问题标题】:const reference to temporary reference对临时引用的 const 引用
【发布时间】:2015-05-23 15:09:30
【问题描述】:
#include <iostream>
using namespace std;

struct CL
{
    CL()
    {
        cout<<"CL()"<<endl;
    }
    CL(const CL&)
    {
        cout<<"CL(const CL&)"<<endl;
    }
    ~CL()
    {
        cout<<"~CL()"<<endl;
    }
};

CL cl;

CL fnc()
{
    return cl;
}

int main() {
    cout<<"start"<<endl;
    const CL& ref=static_cast<const CL&>(fnc());
    //...Is "ref" valid here??
    cout<<"end"<<endl;
    return 0;
}

fnc() 返回的临时对象的生命周期是多少?是“ref”的生命周期还是临时引用 static_cast(fnc()) 的生命周期,在语句结束时销毁?

gcc 的输出(fnc() 的生命周期是“ref”的生命周期):

CL()  //global object "cl"
start
CL(const CL&)
end
~CL()
~CL() //global object "cl"

VS2013 的输出(fnc() 的生命周期是临时引用的生命周期):

CL()  //global object "cl"
start
CL(const CL&)
~CL()
end
~CL() //global object "cl"

标准中什么是正确的?

【问题讨论】:

  • 只是想知道,如果删除 static_cast&lt;&gt; 会发生什么?我希望两者的行为相同,以防万一您有真正想要解决的问题。另外,您对这个问题的标准有何解释?
  • @UlrichEckhardt static_cast 是这里与众不同的地方。没有它,fnc() 的生命周期保证会延长到 ref 的生命周期。
  • 谢谢,@Angew。我知道这是它必须的行为方式,但我只是想确认这个无可争议的规则得到正确实施。
  • @Jean-BaptisteYunès 不是重复的,它不涵盖此问题中提出的问题。

标签: c++ reference language-lawyer temporary-objects


【解决方案1】:

我相信 Visual Studio 在这里是正确的,defect report #1376 对此进行了介绍:

在声明中

T&& r = static_cast<T&&>(T());

不清楚 T 临时的生命周期应该是多少。 根据 5.2.9 [expr.static.cast] 第 4 段,static_cast 是 相当于一个发明的临时变量 t 的声明。这 临时的生命周期延长到 t 的生命周期,但不是 清楚那个生命周期应该是什么,也不知道 t 的后续绑定是否 to r 会影响原始临时文件的生命周期。 (也可以看看 第 1568 期。)

讨论包括这个结论:

引用绑定到 static_cast 的 xvalue 结果,因此不会延长临时对象的生命周期,并且此示例导致悬空引用。

defect report 1568 更具体地介绍了这种情况:

根据 12.2 [class.temporary] 第 4-5 段,

在两种情况下,临时对象在与完整表达式结尾不同的点被销毁...

第二个上下文是引用绑定到临时的。引用绑定到的临时对象或被绑定的临时对象 引用绑定到的子对象的完整对象 在引用的生命周期内持续存在...

不清楚这是否适用于以下示例:

struct S { };
const S& r = (const S&)S();

得到的回应是:

此问题与问题 1376 重复。

所以在这种情况下:

const CL& ref=static_cast<const CL&>(fnc());

引用绑定到static_cast 的结果而不是CL,因此CL 是一个悬空引用。

参考C++11标准部分草案5.2.9的相关文本[expr.static.cast]

否则,表达式 e 可以使用 static_cast 形式的 static_cast 显式转换为类型 T cast(e) 如果声明 T t(e);对于一些发明的临时变量 t (8.5) 是良构的。这 这种显式转换的效果与执行声明和初始化相同,然后 使用临时变量作为转换的结果。表达式 e 用作泛左值 if 和 仅当初始化将其用作 glvalue 时。

【讨论】:

  • DR1376 的分辨率并没有出现在 C++17 中,所以这个故事似乎还有更多内容;我不清楚static_cast 实现的临时对象的生命周期是多少。如果它等效绑定到声明 T t(e) 的结果,那么 t 将持续到当前块的末尾(当前版本的 g++ 和 clang 实际上都是这样做的)
猜你喜欢
  • 2010-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-02
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
相关资源
最近更新 更多