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

oli*_*bre 5 c++ scope reference const-reference temporary-objects

在提出这个问题的时候,我学会了对一个临时对象的const引用在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;
}
Run Code Online (Sandbox Code Playgroud)

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

#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;
}
Run Code Online (Sandbox Code Playgroud)

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

$> g++ -g refnop.cpp
$> ./a.out ; echo $?
4
Run Code Online (Sandbox Code Playgroud)

ref和之间的区别refnopnothing()什么都没有.看来这个调用后,临时对象被破坏了!

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

Bar*_*nau 10

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

令你困惑的案例

A const& refnop = A(a).nothing();
Run Code Online (Sandbox Code Playgroud)

类似于这种情况:

A const& foo(A const& bar)
{
    return bar;
}
//...
A const& broken = foo(A());
Run Code Online (Sandbox Code Playgroud)

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

由于寿命延长属性是非传递,返回一个参考(即恰好是指一个临时对象)将不会进一步延长临时对象的生存期,以作为结果,这两个refnopbroken最后指不再存在的对象.