临时函数参数的生命周期是多久?

78
在将一个新的MyClass实例作为函数的参数时,像这样创建一个新的实例:
class MyClass
{
  MyClass(int a);
};    

myFunction(MyClass(42));

标准是否对析构函数的时机做出任何保证?
具体来说,我能否假设它会在调用myFunction()后的下一条语句之前被调用?

1
相关:https://dev59.com/rHE95IYBdhLWcg3wd9tK - GManNickG
4个回答

123

临时对象在它们所属的完整表达式结束时被销毁。

完整表达式是指不是其他表达式的子表达式的表达式。通常这意味着它以;结尾(或者对于ifwhileswitch等语句,以)结尾),表示语句的结束。在你的示例中,它是函数调用的结尾。

请注意,您可以通过将临时对象绑定到const引用来延长其生命周期。这样做会将它们的寿命延长到引用的生命周期:

MyClass getMyClass();

{
  const MyClass& r = getMyClass(); // full expression ends here
  ...
} // object returned by getMyClass() is destroyed here

如果您不计划更改返回的对象,则这是一个很好的技巧,可以节省复制构造函数调用(与MyClass obj = getMyClass();相比),以防未应用返回值优化。不幸的是,这并不是很出名。(我想C++11的移动语义会使它变得不那么有用。)


1
@sbi 完整表达式在 ) 结束。整个东西可能是一个“完整语句”,但不是“完整表达式”。同样,在 for(iterator i = begin(); i<end; i++) { ... } 中,编译器不需要保留由 i++ 产生的临时迭代器,直到 for 语句结束,当然。这些临时变量只会在其完整表达式结束后存活,这种情况下也是在 ) 处。 - Johannes Schaub - litb
2
你说得很正确:“完整表达式是指不是其他表达式的子表达式的表达式。”在 while、if 和 switch 语句中,我们在 () 之间有一个完整的表达式,因为它们所在的语句根本不是表达式。按照你的解释,; 的结尾根本不是完整表达式的结束,因为如果你在 while/if 或 switch 中,它周围有一个更大的“表达式”。我认为很容易看出这没有任何意义 :) - Johannes Schaub - litb
2
@Johannes:我改了它。<叹气>在这么多年的C++编程中,每周你仍然能学到一些东西。 - sbi
3
我没想到你可以通过使用const引用来延长临时对象的生命周期。好好知道了! - Ferruccio
5
在C++11中,右值引用还可以延长临时变量的生命周期。但出于性能考虑,我不会担心使用其中任何一个。我期望任何优化编译器在这里都会应用复制/移动省略,使两个版本编译为相同的代码(按值捕获或绑定到引用)。 - David Stone
显示剩余3条评论

29

大家都正确引用了12.2/3或类似的内容,这回答了你的问题:

临时对象在计算出包含它们所在点的(词法上的)完整表达式的最后一步被销毁。

我觉得有趣的是,在标准文件的下一页,我的打印中12.2/4说:

有两个环境,在这些环境下,临时对象被销毁的时间点不同于完整表达式的结尾。

两者都与初始化程序中使用临时对象有关,但这确实表明,当处理像C++标准这样棘手的东西时,你必须要保持头脑清醒。


1
如果第二个引用是有意对齐的,从一页开始到下一页结束,那将非常棒。 :-) - Frerich Raabe
4
哇,谢谢你提到这个“例外”。在初始化程序中使用临时变量正是我曾经碰到的情况。 - Dimitar Asenov

10

标准确实提供了保证-来自第12.2 / 5节:

函数调用(5.2.2)中引用参数的临时绑定会持续到包含该调用的完整表达式完成为止

但是,在您的代码中,不清楚参数是按引用传递还是按值传递,尽管在某个时候将使用一个接受引用的复制构造函数。


是否有关于调用函数或被调用函数调用按值传递参数的析构函数的部分?通过检查VS2013的反汇编代码(未知clang或gcc),被调用的函数在返回之前调用了析构函数。这对stdcall来说是可以理解的,因为被调用者在返回之前会弹出参数,但这对cdecl来说却让人感到惊讶(虽然可以理解为避免代码重复)。 - Dwayne Robinson

3
在第12.2节“临时对象”中,第3条款,ANSI/ISO C标准规定:“……临时对象在评估包含它们创建点的(词法)完整表达式的最后一步中被销毁。”
这与序列点的概念密切相关。当到达序列点时,保证所有表达式的副作用已经发生。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接