jot*_*tik 35 c++ arguments function object-lifetime language-lawyer
如果某些函数f
带有参数p_1
,...,p_n
类型T_1
,...,T_n
分别用参数调用a_1
,......,a_n
并且它的正文抛出异常,则完成或返回,参数被破坏的顺序是什么?为什么?如果可能,请提供标准参考.
编辑:我实际上想询问函数"参数",但是由于TC和Columbo设法清除了我的困惑,我将这个问题留下来讨论参数并询问一个关于参数的新单独问题.有关区别,请参阅有关此问题的评论.
Zer*_*ges 21
我无法在标准中找到答案,但我能够在3个最受欢迎的C++兼容编译器上进行测试.R Sahu的答案几乎解释了它是实现定义的.
§5.2.2/ 8:对后缀表达式和参数的评估都是相对于彼此的无法排序的.在输入函数之前,对参数评估的所有副作用进行排序.
Visual Studio C++编译器(Windows)和gcc(Debian)
参数的构造顺序与它们的声明相反,并以相反的顺序销毁(因此按照退出的顺序销毁):
2
1
-1
-2
Clang(FreeBSD)
参数按其声明的顺序构建,并按相反的顺序销毁:
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.);
}
Run Code Online (Sandbox Code Playgroud)
650*_*502 14
在§5.2.2[4]中,N3337对发生的事情非常明确(在线草案):
在参数的初始化期间,实现可以通过将关联参数上的转换和/或临时构造与参数的初始化相结合来避免构建额外的临时值(参见12.2).参数的生命周期在定义它的函数返回时结束.
所以例如在
f(g(h()));
Run Code Online (Sandbox Code Playgroud)
调用的返回值h()
是一个临时值,将在完整表达式结束时销毁.但是,允许编译器避免这种临时性,并使用其值参数直接初始化g()
.在这种情况下,返回值将在返回时被销毁g()
(即在调用之前f()
).
如果我正确理解标准中所述的内容,则不允许将返回的值保存h()
到完整表达式的末尾,除非复制(参数)并且一旦g()
返回就销毁该副本.
这两种情况是:
h
返回值用于直接初始化g
参数.g
返回时和调用之前,此对象将被销毁f
.h
返回值是暂时的.复制是为了初始化g
参数,它在g
返回时被销毁.相反,原始临时表在完整表达式的末尾被销毁.我不知道实现是否遵循相关规则.
R S*_*ahu 11
标准未指定评估函数的参数的顺序.从C++ 11标准(在线草案):
5.2.2函数调用
8 [ 注意:后缀表达式和参数表达式的评估都是相对于彼此的未经测序的.在输入函数之前,对参数表达式评估的所有副作用进行排序(参见1.9).- 尾注 ]
因此,完全取决于实现来决定以什么顺序来评估函数的参数.反过来,这意味着参数的构造顺序也依赖于实现.
合理的实施将以与其构造相反的顺序破坏对象.
归档时间: |
|
查看次数: |
1923 次 |
最近记录: |