【问题标题】:Can anyone tell me when called terminate(), and when unexpected()?谁能告诉我何时调用终止()以及何时调用意外()?
【发布时间】:2013-03-05 04:25:16
【问题描述】:

函数 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()函数? 什么时候被称为破坏者?我找不到逻辑:(((((((()

【问题讨论】:

  • 当它所属的类的实例超出范围时,将调用析构函数。在你的情况下,那永远不会,因为你没有 A 的实例。

标签: c++ exception terminate


【解决方案1】:

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

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

15.1 抛出异常
第 8 段:

如果当前没有处理异常,则执行不调用操作数的 throw 表达式 终止()(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。没有什么能阻止它这样做。

【讨论】:

  • 感谢您的回答,但为什么在我的示例中调用 abort() 在函数 f() 之后?
  • @GrigorApoyan:因为f 回来了。因为它返回,所以它不是一个合适的终止处理程序,所以你有 UB。 (ISO/IEC 14882:2011 18.8.3.1/2:要求的行为:terminate_handler 应终止程序的执行而不返回调用者。)
  • @GrigorApoyan:原因正是 Charles Bailey 所说的,我更新了答案以添加相关引用。
  • @CharlesBailey:嗯……我指的是 C++03 标准。
  • @AlokSave:对不起,我没看到;我一定要失明了。仅供参考,03 标准已被撤销。
【解决方案2】:

谁能告诉我什么时候调用终止(),什么时候调用意外()?

在您的情况下,您的终止处理程序将被调用。你可以验证这个here

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

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

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

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

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

— 当堆栈展开 (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)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-14
    • 1970-01-01
    • 2018-01-21
    • 1970-01-01
    • 2011-01-29
    • 1970-01-01
    相关资源
    最近更新 更多