临时绑定到引用参数的默认参数的生命周期是多少?

时间:2012-09-23 17:38:29

标签: c++ language-lawyer lifetime temporary-objects

我认为引用只会将临时工具的生命周期延长到引用本身的生命周期,但以下代码段的输出似乎是矛盾的:

#include <iostream>

struct X{ ~X(){ std::cout << "Goodbye, cruel world!\n"; } };

X const& f(X const& x = X()){
  std::cout << "Inside f()\n";
  return x;
}

void g(X const& x){
  std::cout << "Inside g()\n";
}

int main(){
  g(f());
}

Live example.输出:

Inside f()
Inside g()
Goodbye, cruel world!

所以看来g()被调用后,临时性被破坏了......是什么给了什么?

2 个答案:

答案 0 :(得分:15)

标准在§12.2 [class.temporary]

的特殊情况下处理此问题
  

p4有两种情况,临时表在与完整表达结束时不同的地方被摧毁。 [...]

     

p5第二个上下文是指引用绑定到临时的。引用绑定的临时值或作为绑定引用的子对象的完整对象的临时值在引用的生命周期内持续存在,除了:

     
      
  • 函数调用中的引用参数的临时绑定(5.2.2)一直持续到包含调用的完整表达式完成。
  •   

该标准还有一个关于全表达式的便利说明以及它们在§1.9 [intro.execution] p11中关于默认参数的子表达式的评估:

  

[注意:对完整表达式的评估可以包括对词汇表的评估,这些子表达式不是词法表达式的全部表达式。例如,计算默认参数(8.3.6)中涉及的子表达式被认为是在调用函数的表达式中创建的,而不是定义默认参数的表达式。 -end note ]

答案 1 :(得分:1)

有趣,+ 1。 (我不是故意在这里与你的好自己的答案竞争)。对于任如果你想要类似的效果,但允许非const,你可以使用移动语义:

#include <iostream>

struct X{
   ~X(){ std::cout << "Goodbye, cruel world!\n"; }
   X(X && x){  std::cout << "moved "; }
   X(){}
};

X  f(X x = X()){
  std::cout << "Inside f()\n";
  return x;
}

void g(X x){
  std::cout << "Inside g()\n";
}

int main(){
   g(f());
}

给出

Inside f()
moved Inside g()
Goodbye, cruel world!
Goodbye, cruel world!