堆栈是否有c ++标准保证的异常展开?

时间:2016-10-10 16:45:21

标签: c++ c++11 language-lawyer

关于堆栈展开,c ++标准说:

  

在完成异常对象([except.throw])的初始化之后,异常被认为是未捕获的,直到完成异常处理程序的激活([except.handle])。这包括堆栈展开。

目前标准的par 15.5.3。我试图理解最新的句子(This includes stack unwindings)是指什么:

  • 是否认为编译器必须负责展开堆栈?
  • 或者,它是说依赖于编译器是否放松堆栈?

问题来自以下片段:

#include <iostream>
#include <exception>

struct S{
    S() { std::cout << " S constructor" << std::endl; }
    virtual ~S() { std::cout << " S destructor" << std::endl; }
};

void f() {
    try{throw(0);}
    catch(...){}
}

void g() {
    throw(10);
}

int main() {
    S s;
    f();
    //g();
}

现在:

  1. 如果按原样运行(捕获异常),则会显示堆栈展开的提示
  2. 如果您发表评论f();并取消注释g();(未捕获异常),则表示您有未显示已展开的堆栈提示
  3. 所以,这两个实验似乎赞成上面的第一个子弹; clang ++和g ++都同意结果(但它不是判别式)。

    另外,我觉得非常奇怪的是,在指定对象实时时间持续时间时非常小心的标准在这里留下了阴影。

    愿任何人澄清吗?堆栈是否为标准保证的未捕获异常展开?如果是的话,在哪里?如果没有,为什么?

1 个答案:

答案 0 :(得分:31)

  

标准保证的未捕获异常的堆栈展开吗?

只有捕获的异常([except.handle] / 9)才能保证堆栈展开:

  

如果找不到匹配的处理程序,则调用函数std::terminate();在对std::terminate()的调用是否为实现定义之前,堆栈是否已展开。

所以它是实现定义的,否则。

  

如果没有,为什么?

如果发生未捕获的异常,标准会导致std::terminate被调用。这表示程序执行的结束。如果您有一些特定于平台的方法来记录当时系统状态的信息,您可能不希望堆栈展开会干扰该状态。

如果你不这样做......那你就不在乎。

如果您真的需要堆栈始终展开,那么您可以将main代码(和任何线程函数)放在try {} catch(...) {throw;}块中。