函数参数的破坏顺序是什么?

如果分别用参数a_1 ,…, a_n调用types为T_1 ,…, T_n参数为p_1 ,…, p_n的函数f ,并且它的主体抛出一个exception,按照什么顺序完成或返回争论被毁,为什么? 如果可能,请提供标准参考。

编辑:我其实想问一下关于函数的“参数”,但是当TC和Columbo设法解决了我的困惑时,我将这个问题留给了参数,并且询问了一个关于参数的新的单独问题 。 请参阅关于这个问题的评论。

标准中没有规定函数参数的求值顺序。 从C ++ 11标准( 在线草案 ):

5.2.2函数调用

8 [ 注:后缀expression式和参数expression式的评估是相互不相关的。 参数expression式评估的所有副作用在input函数之前都被sorting(见1.9)。 – 注意 ]

因此,完全由一个实现决定以什么顺序来评估一个函数的参数。 这又意味着参数的构build顺序也是实现依赖的。

一个明智的实施会以相反的顺序摧毁对象。

我没有设法在标准中find答案,但我能够在3种最stream行的C ++兼容编译器上进行testing。 R Sahu的回答很好的解释了它是实现定义的。

§5.2.2/ 8 :后缀expression式和参数的评估都是相互不相关的。 在input函数之前,参数评估的所有副作用都被sorting。

Visual Studio C ++编译器(Windows)和gcc(Debian)
这些论据是按照与声明相反的顺序构build的,并以相反的顺序销毁(按照sorting的顺序销毁):

2
1
-1
-2

铿锵(FreeBSD)
参数是按照声明的顺序构build的,并按相反的顺序销毁:

1
2
-2
-1

指示所有编译器将源代码作为C ++ 11处理,并使用以下代码片段来演示情况:

 struct A { A(int) { std::cout << "1" << std::endl; } ~A() { std::cout << "-1" << std::endl; } }; struct B { B(double) { std::cout << "2" << std::endl; } ~B() { std::cout << "-2" << std::endl; } }; void f(A, B) { } int main() { f(4, 5.); } 

在§5.2.2中[4] N3337对发生的事情( 在线草案 )非常明确:

在初始化一个参数的过程中,一个实现可以通过将相关参数和/或临时对象的转换与参数的初始化(参见12.2)相结合来避免构造额外的临时对象。 一个参数的生命周期在其定义的函数返回时结束。

所以例如在

 f(g(h())); 

调用h()的返回值是一个在完整expression式结束时被销毁的临时值。 但是编译器可以避免这个临时的,并且直接用它的值来初始化g()的参数。 在这种情况下,一旦g()返回(即在调用f()之前g() ,返回值就会被销毁。

如果我正确地理解了标准中的内容,但是不允许从h()返回的值存活到完整expression式的结尾,除非做了一个拷贝(参数),并且这个拷贝一旦被g()回报。

这两种情况是:

  1. h返回值用于直接初始化g参数。 当g返回时,在调用f之前,该对象被销毁。
  2. h返回值是暂时的。 复制是为了初始化g参数,并在g返回时被销毁。 原来的临时代码在完整expression式的末尾被销毁。

我不知道实现是否遵循这个规则。