2

当函数 f() 和 g() 结束时会发生什么?

#include<iostream>
using namespace std;

class A
{
     ~A(){}

}
void f()
{
    cout << "terminate" << endl;

}
void g()
{
    cout << "unexpected" << endl;
}



int main()
{
    set_terminate(f);
    set_unexpected(g);
    throw 5;
    cout << "end" << endl;
    return 0;
}

为什么叫 abort() 函数?什么时候被称为破坏者?我找不到逻辑:(((((((((

4

2 回答 2

3

谁能告诉我何时调用终止()以及何时调用意外()?

在您的情况下,将调用您的终止处理程序。您可以在此处验证这一点。

关于std::terminate(),第 15.5.1/1-2 段包含一个注释,其中列出了它被调用的情况的非常详尽的列表(粗体部分适用于您的情况):

1 在某些情况下,必须放弃异常处理以使用不太微妙的错误处理技术。[注:这些情况是:

— 当异常处理机制在完成异常对象的初始化之后但在激活异常处理程序之前(15.1)调用通过异常退出的函数,或

当异常处理机制无法找到抛出异常的处理程序时(15.3),或

— 当搜索处理程序 (15.3) 遇到具有不允许异常 (15.4) 的 noexcept 规范的函数的最外层块时,或

— 当堆栈展开(15.2)期间对象的破坏因抛出异常而终止时,或

— 当具有静态或线程存储持续时间(3.6.2)的非局部变量的初始化通过异常退出时,或

— 当通过异常(3.6.3)退出具有静态或线程存储持续时间的对象时,或

— 当执行注册std::atexitstd::at_quick_exit通过异常(18.5)退出的函数时,或

— 当没有操作数的 throw 表达式尝试重新抛出异常并且没有处理异常时 (15.1),或

— 当std::unexpected抛出先前违反的动态异常规范不允许的异常,并且 std::bad_exception 不包含在该动态异常规范 (15.5.2) 中,或

— 当调用实现的默认意外异常处理程序时 (D.11.1),或

— 当std::nested_exception::rethrow_nested为未捕获异常的对象调用函数时(18.8.6),或

— 当线程的初始函数的执行通过异常(30.3.1.2)退出时,或

— 当在 std::thread 类型的对象上调用析构函数或复制赋值运算符时,该对象引用可连接线程(30.3.1.3、30.3.1.4)。——尾注]

2 在这种情况下,std::terminate()称为 (18.8.3)。[...]

关于std::unexpected(),根据第 15.4/9 段:

每当抛出异常并且搜索处理程序 (15.3) 遇到具有不允许异常的异常规范的函数的最外层块时,然后,

— 如果异常规范是动态异常规范,std::unexpected()则调用该函数(15.5.2),

— 否则,调用函数 std::terminate() (15.5.1)。

于 2013-03-16T13:11:46.243 回答
1

标准中明确定义了相关规则,有许多规则,但简单地说,适用于您的示例的规则是:

  • throw没有catch结果调用terminate或为其设置的函数。
  • 当抛出的异常与异常规范不匹配时,会调用 unexpected或为其设置函数。

15.1 抛出异常
第 8 段:

如果当前没有处理异常,则执行不带操作数的 throw 表达式调用 terminate() (15.5.1)。

15.4 例外规范
第 8 段:

每当抛出异常并且对处理程序 (15.3) 的搜索遇到具有异常规范的函数的最外层块时,如果异常规范不允许异常,则调用函数 unexpected() (15.5.2)


为什么你的程序调用abort

您的程序具有未定义的行为。它符合您terminate_handler适当设置的事实,并且您注意到程序确实会导致调用,f()但函数所需的行为terminate_handler是:

C++03 标准 18.6.3.1.2:

terminate_handler 将终止程序的执行而不返回给调用者。

您的terminate_handler函数f不满足此条件,因此会导致未定义的行为,从技术上讲,您可能会获得任何行为,您的实现选择abort在这种情况下调用。没有什么能阻止它这样做。

于 2013-03-16T13:11:37.543 回答