对临时引用的const引用

8
#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<> 会发生什么?我期望两者的行为都应该相同,以防你有一个真正想要解决的问题。另外,你对标准关于这个问题的解释是什么? - Ulrich Eckhardt
1
@UlrichEckhardt 这里的关键是 static_cast。如果没有它,fnc() 的生命周期将会被保证延长到 ref 的生命周期。 - Angew is no longer proud of SO
1
@Jean-BaptisteYunès 这不是重复的,它没有涵盖这个问题中提出的问题。 - Shafik Yaghmour
@ShafikYaghmour 我并不是想说 OP 的问题的答案很明确。我只是想说 没有 static_cast 的情况下是这样的。 - Angew is no longer proud of SO
@Angew 哦,这很有道理,我在想为什么你没有回答;-) - Shafik Yaghmour
显示剩余3条评论
1个回答

5

我相信Visual Studio是正确的,这在缺陷报告#1376中有所涵盖,该报告表示:

In a declaration like

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

it is not clear what the lifetime of the T temporary should be. According to 5.2.9 [expr.static.cast] paragraph 4, the static_cast is equivalent to a declaration of an invented temporary variable t. The lifetime of the temporary is extended to that of t, but it is not clear what that lifetime should be, nor if the subsequent binding of t to r would affect the lifetime of the original temporary. (See also issue 1568.)

讨论包括以下结论:

引用被绑定到static_cast的xvalue结果,因此临时对象的生命周期未延长,这个例子导致了悬空引用。

缺陷报告1568更具体地涵盖了这种情况:

According to 12.2 [class.temporary] paragraphs 4-5,

There are two contexts in which temporaries are destroyed at a different point than the end of the full-expression...

The second context is when a reference is bound to a temporary. The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference...

It is not clear whether this applies to an example like the following:

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]的相关文本:
否则,如果对于某个虚构的临时变量t(8.5),声明T t(e);是良好形式的,则表达式e可以使用形如static_cast(e)的static_cast显式转换为类型T。这种显式转换的效果与执行声明和初始化,然后使用临时变量作为转换结果相同。当且仅当初始化将其用作glvalue时,表达式e才被用作glvalue。

DR1376的解决方案似乎在C++17中没有出现,所以这个问题可能还有更多的内容;我不清楚通过static_cast实例化的临时对象的生命周期是什么。如果它与声明T t(e)的结果具有等效绑定,则t将持续到当前块的末尾(当前版本的g++和clang都是这样做的)。 - M.M

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接