11

C++ 标准提供了允许您指定实际调用的std::set_terminate函数的函数。应该只在可怕的情况下被调用,并且当它被调用时,标准描述的情况确实是可怕的(例如未捕获的异常)。什么时候被调用,这种情况似乎类似于失忆——你可以明智地做的事情并不多。std::terminatestd::terminatestd::terminate

我读过它可以用来确保资源被释放——但对于大多数资源,这应该由操作系统在进程退出时自动处理(例如文件句柄)。从理论上讲,我可以看到一个案例,如果说,由于崩溃而退出时,您需要向服务器发送特定消息。但大多数时候操作系统处理应该足够了。

什么时候使用终止处理程序才是正确的?

更新:对自定义终止处理程序可以做什么感兴趣的人可能会发现这个不可移植的技巧很有用。

4

3 回答 3

7

这只是乐观的:

但是对于大多数资源,这应该由操作系统在进程退出时自动处理

操作系统自动处理的唯一资源是“文件句柄”和“内存”(这可能因操作系统而异)。实际上,所有其他资源(如果有人有一个由操作系统自动处理的资源列表,我会喜欢的)需要由操作系统手动释放。

最好的办法是避免使用 terminate() 退出,并通过强制堆栈正确展开来尝试受控关闭。这将确保正确调用所有析构函数并释放您的资源(通过析构函数)。

关于我唯一要做的就是记录问题。这样当它发生时,我可以回去修复代码,这样它就不会再次发生。我喜欢我的代码很好地展开堆栈以进行资源释放,但这是一些人喜欢在事情变得糟糕时突然停止的观点。

我的终止时间列表被称为:

通常,当异常处理机制无法找到抛出异常的处理程序时调用它。一些具体的例子是:

  • 异常转义 main()
    • 注意:此处是否展开堆栈由实现定义。因此,我总是在 main 中捕获然后重新抛出(如果我没有明确处理)。这样我就保证了堆栈的展开(跨所有平台)并且仍然可以获得操作系统异常处理机制的好处。
  • 两个异常同时传播。
    • 当另一个异常正在传播时,一个异常会从析构函数中逃脱。
    • 抛出的表达式会产生异常
  • main 之前或之后的异常。
    • 如果异常转义了全局对象的构造函数/析构函数。
    • 如果异常转义函数静态变量的析构函数。(即小心非本地静态对象的构造函数/析构函数)
    • 异常会转义使用 atexit() 注册的函数。
  • 当前没有异常传播时重新抛出。
  • 未列出的异常会转义具有异常说明符列表的方法/函数。
    • 通过意外。
于 2009-06-29T15:20:28.673 回答
0

与Martin York 的 回答类似,我在自定义终止处理程序中所做的唯一一件事就是记录问题,以便我可以识别和更正有问题的代码。这是我发现使用自定义终止处理程序是正确的唯一实例。


由于在调用之前是否展开堆栈是实现定义的std::terminate(),因此我有时会添加代码以生成回溯以定位未捕获的异常1

1) 在 Linux 平台上使用 GCC 时,这似乎对我有用。

于 2010-04-14T23:28:02.783 回答
-1

我认为正确的问题是如何避免调用终止处理程序,而不是何时使用它。

于 2009-06-29T15:09:03.033 回答