函数参数的销毁顺序是什么?

17

这是我之前的一个问题函数参数的销毁顺序是什么?的后续,因为我不小心混淆了参数和函数。感谢Columbo和T.C.在那个问题的评论中帮我澄清了术语混淆。

如果某个带有类型分别为T_1, ..., T_n的参数p_1, ..., p_n的函数f的主体抛出异常、完成或返回,那么参数的销毁顺序是什么,为什么?如果可能,请提供对标准的引用。

例子:

template <typename ... Args>
void f(Args ... params) {} // in what order are params destroyed?

void f(T1 p1, T2 p2, T3 p3) {} // in what order are p1, p2 and p3 destroyed?

2
我认为在评估顺序方面,抛出异常并没有太大的区别。 - πάντα ῥεῖ
1个回答

14

参数被销毁的确切时间是未指定:

CWG决定不具体说明参数对象是在调用后立即销毁还是在调用所属完整表达式的结尾处销毁。

参数构造的顺序也未指定,但由于函数参数具有块作用域,虽然它们的构造顺序是未指定的,销毁顺序与构造顺序相反。例如,请考虑:

#include <iostream>

struct A {
    int i;
    A(int i) : i(i) {std::cout << i;}
    ~A() {std::cout << '~' << i;} 
};

void f(A, A) {}

int main() {
    (f(0, 1), std::cout << "#");
}

打印 10#~0~1 使用GCC,并使用Clang打印01#~1~0;它们以不同的顺序构建参数,但在完整表达式结束时销毁(而不是在返回给调用者后立即销毁)。 VC++打印10~0~1#


2
销毁顺序是否要求与构造顺序相反? - M.M
1
“参数没有自动存储期限”是什么意思? - T.C.
1
@M.M 注意,参数之间的依赖关系也可以在它们构建完成之后,在执行函数体时引入。通常情况下,这可能不明智,但是在某些情况下可能会变得实用。 - jotik
3
@Columbo 嗯…函数参数的作用域受 [basic.scope.block] 和标准的其他位置的覆盖,明确地将它们视为自动变量(例如,[class.copy]/31-32)。 - T.C.
3
为了确保生活不会无聊,MSVC打印出10~0~1#(析构函数从f中调用)。 - bogdan
显示剩余10条评论

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