通过const引用临时延长寿命

时间:2013-10-10 22:00:23

标签: c++ object-lifetime temporary-objects const-reference scopeguard

C ++

我试图看看const引用如何延长临时工的寿命。我在one of the answers to What are the differences between pointer variable and reference variable in 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");
}

回答者得到了结果:

in scope
scope_test done!

我在VC11中试过它并得到了这个:

scope_test done!
in scope
scope_test done!

我认为VC11结果是由缺少复制省略引起的,所以我试着看看用fno-elide-constructors禁用g ++上的复制省略是否会给出与VC11相同的结果。 (我不认为复制省略可以在VC11中切换。)但是,无论标志的设置如何,g ++都会给出回答者的结果。

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

  

有两种情况下,临时状态被摧毁   不同于完整表达的结束......

     

第二个上下文是引用绑定到临时的。该   临时引用的临时或临时的   引用绑定到的子对象的完整对象   在参考文件的生命周期内持续存在,除了:

     

...

VC11结果与copy elision有什么关系?它是VC11的错误吗?

回答者说:

  

分配给const引用的临时值直到const   参考超出范围

§12.2/ 5的例外列表不排除non-const引用。我在标准中缺少什么?

删除VC11中的const会产生与带有const的VC11相同的结果。删除g ++中的const会产生error: invalid initialization of non-const reference of type ‘scope_test&’ from an rvalue of type ‘scope_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");
}

无论复制省略的切换如何,g ++都会给出:

regular ctor
in scope
scope_test done!

即使const被删除,VC11也会提供相同的功能。如果从g ++中删除const,g ++仍会提供error: invalid initialization of non-const reference of type ‘scope_test&’ from an rvalue of type ‘scope_test’

1 个答案:

答案 0 :(得分:2)

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

  

否则,引用应为非易失性const类型(即,cv1应为const)。 [例如:......]

     
      
  • 如果初始化表达式是rvalue,T2是类类型,并且“cv1 T1”与“cv2 T2”引用兼容,则引用以下列方式之一绑定(选择是实现-defined):

         

    - 引用绑定到rvalue(参见3.10)表示的对象或该对象中的子对象。

         

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

  •   

我认为C ++ 11的定义仍然允许复制,但措辞并不明确允许复制。无论如何,VC ++并不声称完全符合C ++ 11标准。