在函数作用域(生命周期)之后,对临时对象的 const 引用被破坏

在问这个问题时,我学会了const引用到临时对象在 C++ 中是有效的:

While asking this question, I learned const reference to a temporary object is valid in C++:

int main ()
{
  int a = 21;
  int b = 21;

  //error: invalid initialization of non-const reference
  //int     & sum = a + b;e [...]

  //OK
  int const & sum = a + b;

  return sum;
}

但是在下面的例子中,const 引用 refnop 引用了一个被破坏的临时对象.我想知道为什么?

But in the following example, the const reference refnop refers to a destroyed temporary object. I wonder why?

#include <string>
#include <map>

struct A
{
   // data 
   std::map <std::string, std::string>  m;
   // functions
   const A& nothing()           const { return *this;    }
   void init()                        { m["aa"] = "bb";  }
   bool operator!= (A const& a) const { return a.m != m; }
};

int main()
{
  A a;
  a.init();

  A const& ref    = A(a);
  A const& refnop = A(a).nothing();

  int ret = 0;
  if (a != ref)     ret += 2;
  if (a != refnop)  ret += 4;

  return ret;
}

使用 GCC 4.1.2 和 MSVC 2010 测试,返回 4;

Tested using GCC 4.1.2 and MSVC 2010, it returns 4;

$> g++ -g refnop.cpp
$> ./a.out ; echo $?
4

refrefnop 之间的区别在于对 nothing() 的调用实际上什么都不做.看来这次调用之后,临时对象就被销毁了!

The difference between ref and refnop is the call to nothing() which does really nothing. It seems after this call, the temporary object is destroyed!

我的问题:
为什么在refnop的情况下,临时对象的生命周期与其const引用不同?

My question:
Why in the case of refnop, the life time of the temporary object is not the same as its const reference?

推荐答案

当临时对象绑定到第一个引用时,临时对象的生命周期扩展只能执行一次.之后,引用指向临时对象的知识就消失了,因此无法再延长生命周期.

The lifetime-extension of a temporary object can be performed only once, when the temporary object gets bound to the first reference. After that, the knowledge that the reference refers to a temporary object is gone, so further lifetime extensions are not possible.

让你困惑的案例

A const& refnop = A(a).nothing();

类似于这种情况:

A const& foo(A const& bar)
{
    return bar;
}
//...
A const& broken = foo(A());

在这两种情况下,临时变量都绑定到函数参数(nothing() 的隐式 thisbarfoo()) 并将其生命周期扩展"到函数参数的生命周期.我将'extended'放在引号中,因为临时文件的自然生命周期已经更长,因此不会发生实际的扩展.

In both cases, the temporary gets bound to the function argument (the implicit this for nothing(), bar for foo()) and gets its lifetime 'extended' to the lifetime of the function argument. I put 'extended' in quotes, because the natural lifetime of the temporary is already longer, so no actual extension takes place.

因为生命周期扩展属性是不可传递的,返回一个引用(恰好指向一个临时对象)不会进一步延长临时对象的生命周期,结果是 refnopbroken 最终指向不再存在的对象.

Because the lifetime extension property is non-transitive, returning a reference (that happens to refer to a temporary object) will not further extend the lifetime of the temporary object, with as result that both refnop and broken end up referring to objects that no longer exist.

相关文章