const引用临时引用

use*_*538 7 c++ reference language-lawyer temporary-objects

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

fnc()返回的临时对象的生命周期是多少?它是"ref"或临时引用static_cast(fnc())的生命周期,它在语句结束时被销毁了吗?

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

CL()  //global object "cl"
start
CL(const CL&)
end
~CL()
~CL() //global object "cl"
Run Code Online (Sandbox Code Playgroud)

VS2013的输出(fnc()的寿命是临时参考的寿命):

CL()  //global object "cl"
start
CL(const CL&)
~CL()
end
~CL() //global object "cl"
Run Code Online (Sandbox Code Playgroud)

标准是什么?

Sha*_*our 5

我相信Visual Studio在这里是正确的,这在缺陷报告#1376中有所说明:

在像这样的宣言中

T&& r = static_cast<T&&>(T());
Run Code Online (Sandbox Code Playgroud)

目前尚不清楚T临时的寿命应该是多少.根据5.2.9 [expr.static.cast]第4段,static_cast等同于发明临时变量t的声明.临时的生命周期延长到t的生命周期,但不清楚该生命周期应该是什么,也不知道随后的t与r的绑定是否会影响原始临时的生命周期.(另见问题1568.)

讨论包括这个结论:

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

缺陷报告1568更具体地涵盖了这个案例:

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

有两种情况下,临时演员在与完整表达结束时不同的地方被摧毁......

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

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

struct S { };
const S& r = (const S&)S();
Run Code Online (Sandbox Code Playgroud)

而回应是:

此问题与问题1376重复.

所以在这种情况下:

const CL& ref=static_cast<const CL&>(fnc());
Run Code Online (Sandbox Code Playgroud)

引用绑定到结果static_cast而不是结果,CL因此CL是悬空引用.

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

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