临时的一生

时间:2013-04-17 07:50:40

标签: c++

下面的代码显示在函数create()中创建的对象的生命周期延长到const ref中创建的main的生命周期,在所有情况下都是正确的 ?我的意思是我们可以通过创建对它的引用来延长某些情况下的临时寿命吗?或者在这种特殊情况下,编译器行为不端?

使用MSVC2005编译

#include <iostream>

class testClass
{
public:
    testClass()
    {
        std::cout << "in testClass " << ((void*)this) << std::endl;
    }

    ~testClass()
    {
        std::cout << "in ~testClass " << ((void*)this) << std::endl;
    }
};


testClass create()
{
    return testClass();
}


int main()
{
    {
        testClass const& obj = create();

        std::cout << "we got a const reference to obj " << ((void*)&obj) << std::endl;
    }

    return 0;
}

输出

in testClass 0018FF13
we got a const reference to obj 0018FF13
in ~testClass 0018FF13

当然其他可能会得到不同的地址......在上面的例子中,我期望用函数create()创建的对象的析构函数,将在行之前调用

std::cout << "we got a const reference to obj " << ((void*)&obj) << std::endl; 

已执行。

3 个答案:

答案 0 :(得分:6)

这是一种特殊情况:将 const 引用绑定到临时对象,延长其生命周期,直到该const引用超出范围。这仅适用于函数局部const引用,例如以下内容不起作用:

struct X
{
  int const& i
  X(int const& i_) : i(i_) {}
};

int f();

int main()
{
  X x(f()); 
  int u = x.i; //!
}

在构建x期间,i_将绑定到f返回的临时值,i也是如此,但是虽然它是const引用,但是temporarie的生命周期不会被延伸到i,即规则确实适用于此。

请参阅this GOTW article

更新:如文章和评论中所述,const至关重要。 C ++标准允许将临时值绑定到const左值引用和右值引用,因此不允许int& i = f();。但是,MSVC具有允许此扩展的扩展,并且与其他引用一样,临时的生存期将延长,直到引用超出范围。我不建议使用该扩展,因为它使代码不可移植。事实上,我会小心地将临时文件绑定到引用,因为这个功能并不为人所知,并且你的同事可能会觉得它有效,这意味着代码缺乏可读性。

答案 1 :(得分:2)

澄清 - 我们可以为testClass create()显示3个方案:

1

返回副本但通过const引用

捕获它
testClass create()
{
    return testClass();
}

testClass const &obj = create();

只要testClass(),就可以延长临时obj的续航时间。

2

返回副本并按作业(RVO)捕获

testClass create()
{
    return testClass();
}

testClass obj = create();

只要testClass(),它就会延长临时obj的生命周期,因为RVO隐式适用于它。最好说,实际上这里没有临时对象,即使在obj函数中,所有内容都在create()上运行。

3

返回副本并通过分配捕获它(不含RVO)

testClass create()
{
    return testClass();
}

testClass obj = create();

testClass()返回后,临时create()的续航时间超过了一个新对象。

答案 2 :(得分:1)

link应该可以帮助您了解这种情况是如何合格的。

  

创建临时对象以初始化引用变量时,   临时对象的名称与作用域的名称相同   参考变量。在期间创建临时对象时   评估一个完整的表达式(一个不是一个表达式   另一个表达式的子表达式),它作为最后一步被销毁   在其评价中,词汇上包含了它的位置   创建

     

破坏全表达式有两个例外:

     
      
  • 表达式显示为定义的声明的初始化程序   object:初始化时销毁临时对象   完整。
  •   
  • 引用绑定到临时对象:临时对象   对象在引用的生命周期结束时被销毁。
  •