C ++:临时参数的寿命?


73

在创建新的a实例MyClass作为函数的参数时,如下所示:

class MyClass
{
  MyClass(int a);
};    

myFunction(MyClass(42));

该标准是否对析构函数的时间做出任何保证?

具体来说,我可以假设它将在调用之后的下一个语句之前被调用myFunction()吗?


Answers:


116

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

完整表达式是不是其他表达式的子表达式的表达式。通常,这意味着它在端部处;(或)ifwhileswitch等等)表示的语句的末尾。在您的示例中,函数调用已结束。

请注意,可以通过将临时对象绑定到const参考来延长其寿命。这样做可以将其寿命延长到参考的寿命:

MyClass getMyClass();

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

如果您不打算更改返回的对象,那么这是保存复制构造函数调用(与相比MyClass obj = getMyClass();)的一个好技巧,以防万一没有应用返回值优化。不幸的是,它不是很知名。(不过,我想C ++ 11的move语义会使它的用处不大。)


1
+1个不错的答案。我认为您的意思是)而不是},如果有的话,切换等?if(f(string())) { ... }直到}:)
约翰内斯·绍布

2
您自己正确地说了一下:“完整表达式是不是其他表达式的子表达式的表达式。” 在同时,如果切换情况下,我们在(和之间有一个完整的表达式,)因为它们出现的语句无论如何都不是表达式。在您的解释中,end;根本不会是full-expression-end,因为如果您在while / if或switch内,则它周围会有一个较大的“ expression”。我认为很容易看出这是没有道理的:)
Johannes Schaub-litb 2010年

2
@约翰内斯:我改变了。<感叹>经过这么多年的C ++,您仍然每周都学习一些东西。
2010年

3
我没有意识到您可以使用const引用来延长临时对象的寿命。很高兴知道!
Ferruccio

4
在C ++ 11中,右值引用还可以延长临时项的寿命。但是,出于性能原因,我不必担心使用这两种方法。我希望任何优化的编译器都可以在此处应用复制/移动省略,使两个版本可以编译为相同的代码(按值捕获或绑定到引用)。
戴维·斯通

26

每个人都正确地引用了12.2 / 3或类似的词,它回答了您的问题:

临时对象被销毁是评估(按词法)包含创建点的完整表达式的最后一步。

我发现在我打印该标准的下一页时,12.2 / 4说:

在两种情况下,临时变量在与完整表达式结束时不同的位置被销毁。

它们都不适用于您的示例,它们都与初始化器中的临时使用有关。但这确实表明,在处理像C ++标准这样的棘手野兽时,您必须保持智慧。


1
如果故意将第二个引号对齐以使其在一页上开始并在下一页上结束,那将是非常棒的。:-)
Frerich Raabe

3
哇,谢谢你提到这个“例外”。初始化器中的临时对象正是我所咬的。
Dimitar Asenov

10

该标准确实提供了保证-从12.2 / 5节开始:

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

但是,在代码中,不清楚是通过引用还是通过值传递参数,尽管有时会使用确实采用引用的复制构造函数。


关于调用函数还是被调用函数调用by-value参数的析构函数的任何部分?检查VS2013的反汇编(不知道clang或gcc),被调用函数在返回之前会调用析构函数。对于stdcall来说,这是可以理解的,因为被调用者会在返回之前弹出参数,但是对于cdecl来说,这让我感到惊讶(虽然可以避免代码)。
Dwayne Robinson

3

在12.2节“临时对象”的第3节中,ANSI / ISO C标准规定:“ ...临时对象被销毁,是评估(按词法)包含创建点的完整表达式的最后一步。”

这与序列点的概念密切相关。当到达序列点时,可以保证表达式的所有副作用都已发生。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.