C++ 通过常量引用延长临时文件的使用寿命

C++ 通过常量引用延长临时文件的使用寿命,c++,object-lifetime,temporary-objects,const-reference,scopeguard,C++,Object Lifetime,Temporary Objects,Const Reference,Scopeguard,C++ 我想看看常量引用是如何延长临时变量的寿命的。我正在运行中代码段中的代码,在VC11和g++4.8之间得到了冲突的结果。我在这里展开了这个片段: #include <stdio.h> struct scope_test { ~scope_test() { printf("scope_test done!\n"); } }; int main() { const scope_test& test = scope_test(); printf("

C++

我想看看常量引用是如何延长临时变量的寿命的。我正在运行中代码段中的代码,在VC11和g++4.8之间得到了冲突的结果。我在这里展开了这个片段:

#include <stdio.h>

struct scope_test
{
    ~scope_test() { printf("scope_test done!\n"); }
};

int main()
{
    const scope_test& test = scope_test();
    printf("in scope\n");
}
我在VC11中尝试过,得到了以下结果:

scope_test done!
in scope
scope_test done!
我假设VC11的结果是由于缺少复制省略而导致的,因此我尝试查看使用
fno elide构造函数
在g++上禁用复制省略是否会产生与VC11相同的结果。(我不认为复制省略可以在VC11中切换。)但是,g++给出应答者的结果,而不管标志的设置如何

C++11标准ISO/IEC 14882:2011(E),§12.2/4和/5规定:

有两种情况下,临时机构会在同一时间被销毁 与完整表达式的结尾不同点

第二个上下文是将引用绑定到临时上下文。这个 引用绑定到的临时文件或 引用绑定到的子对象的完整对象 在引用的生存期内持续存在,但以下情况除外:

VC11结果是否与拷贝省略有关?它是VC11错误吗

答复者说:

分配给常量引用的临时变量在常量引用 引用超出范围

§12.2/5的例外情况列表不排除非常量参考。我在标准中遗漏了什么

删除VC11中的常量会产生与使用常量的VC11相同的结果。删除g++中的常量会出现
错误:从“scope\u test”类型的右值初始化“scope\u test&”类型的非常量引用无效。
。为什么会有区别

编辑

我添加了复制和移动构造函数并尝试:

#include <stdio.h>

struct scope_test
{
    scope_test() { printf("regular ctor\n"); }
    scope_test(const scope_test& src) { printf("copy ctor\n"); }
    scope_test(scope_test&& src) { printf("move ctor\n"); }
    ~scope_test() { printf("scope_test done!\n"); }
};

int main()
{
    const scope_test& test= scope_test();
    printf("in scope\n");
}

VC11给出了相同的结果,即使删除了
const
。如果从g++中删除
常量
,g++仍然会给出
错误:从类型为“scope\u test”的右值初始化类型为“scope\u test&”的非常量引用无效

这两种行为都是正确的,当然符合C++03标准(8.5.3[dcl.init.ref]第5段):

否则,参考应为非易失性常数类型(即cv1应为常数)。[示例:…]

  • 如果初始值设定项表达式是一个右值,T2是一个类类型,“cv1 T1”与“cv2 T2”是引用兼容的,那么引用将通过以下方式之一绑定(选项由实现定义):

    -引用绑定到由右值表示的对象(请参见3.10)或该对象内的子对象

    -创建“cv1 T2”[sic]类型的临时对象,并调用构造函数将整个右值对象复制到临时对象中。该引用绑定到临时对象或临时对象中的子对象


我认为C++11的定义仍然允许复制,但措辞不那么清楚地允许复制。在任何情况下,VC++都不会声称完全符合C++11。

但是没有任何复制,因为只有一个对象。
const
与生命周期延长无关。任何参考资料都可以。只是非常量左值引用不能绑定到右值,因此永远不能以这种方式使用。@KerrekSB:将临时值绑定到常量会导致副本构造。验证是否创建了副本的最简单方法是插入副本构造函数。@DietmarKühl:这不是一个返回值的函数,但它实际上是RHS上的一个对象。@KerrekSB:是的,但这些词并不强制将同一对象绑定到具有相同值的对象,即可能是副本8.5.3[dcl.init.ref]第5段:“如果初始值设定项表达式…是一个xvalue…那么引用将绑定到初始值设定项表达式的值…”。C++03更明确地允许复制:“如果初始值设定项表达式是一个右值…引用将通过以下方式之一绑定(选项由实现定义):…并调用构造函数将整个右值对象复制到临时对象中。”(由于空间有限而省略)。通过“两种行为都是正确的”,您的意思是对于具有常量引用的示例或具有非常量引用的示例,VC11和g++输出都是正确的吗?此外,我添加了复制和移动构造函数(请参见编辑).如果VC11示例是
-类型为“cv1 T2”的临时情况[sic]创建,并调用构造函数将整个右值对象复制到临时对象中。引用绑定到临时…
;这是否意味着VC11在这里省略,因为它不输出
copy-ctor
move-ctor
,但在我没有定义自己的复制和移动ctor时不输出?
#include <stdio.h>

struct scope_test
{
    scope_test() { printf("regular ctor\n"); }
    scope_test(const scope_test& src) { printf("copy ctor\n"); }
    scope_test(scope_test&& src) { printf("move ctor\n"); }
    ~scope_test() { printf("scope_test done!\n"); }
};

int main()
{
    const scope_test& test= scope_test();
    printf("in scope\n");
}
regular ctor
in scope
scope_test done!