4

下面的代码显示在函数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; 

被执行。

4

3 回答 3

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, will 绑定到由, as willi_返回的临时对象,但尽管它是一个 const 引用,但临时对象的生命周期不会延长到 的生命周期,即该规则在这里适用。fii

请参阅这篇 GOTW 文章

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

于 2013-04-17T07:57:56.790 回答
2

澄清一下 - 我们可以展示 3 个场景testClass create()

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(),一个新的对象来到了世界。

于 2013-04-17T08:08:24.927 回答
1

链接应该可以帮助您了解这种情况是如何限定的。

当创建临时对象来初始化引用变量时,临时对象的名称与引用变量的名称具有相同的范围。当在对完整表达式(不是另一个表达式的子表达式)求值期间创建临时对象时,它会作为其求值的最后一步被销毁,在词法上包含创建它的点。

全表达式的销毁有两个例外:

  • 该表达式作为定义对象的声明的初始化程序出现:初始化完成时,临时对象被销毁。
  • 引用绑定到临时对象:临时对象在引用的生命周期结束时被销毁。
于 2013-04-17T07:57:01.457 回答