【问题标题】:When is a C++ terminate handler the Right Thing(TM)?C++ 终止处理程序何时是 Right Thing(TM)?
【发布时间】:2010-11-06 17:24:33
【问题描述】:

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

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

Right Thing(TM) 何时使用终止处理程序?

更新:People interested in what can be done with custom terminate handlers might find this non-portable trick useful.

【问题讨论】:

  • std::terminate 应该只在可怕的情况下被调用,而且当它被调用时,标准描述的情况确实是可怕的(例如,一个未捕获的异常)。
  • 不,他的意思是未捕获的异常。
  • 是的,找到了。包罗万象的短语:(异常处理机制找不到抛出异常的处理程序。)

标签: c++ exception-handling resources standards terminate


【解决方案1】:

这只是乐观:

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

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

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

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

我的终止时间列表:

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

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

【讨论】:

  • 实际上,我有兴趣查看当进程终止时现代操作系统无法恢复的资源列表。 AFAIK,所有资源(如套接字、互斥锁)都由 Linux 和 Windows 恢复。如果不是这种情况,很难看到如何拥有可靠的服务器操作系统。
  • 我相信尼尔是正确的。当然,C++ 并不总是在现代操作系统上运行;)
  • 未恢复是巨大的。它的任何东西都不足以由操作系统管理。数据库连接c,链接到国际空间站:-)。甚至套接字也没有很好地处理。在 Linux 上如果你杀死了一个监听 Socket 的应用程序,该套接字在操作系统清理之前的几分钟内仍然不可用。在 windows 文件上处理得不是特别好。我多久需要重新启动一次,因为某些死应用程序仍在保留文件(文件句柄可能已被清理,但文件系统仍然认为该文件正在被使用)阻止我删除它。
  • 开始了一个问题来回答这个难题。 stackoverflow.com/questions/1060160/…
  • 当应用程序死掉时文件被关闭。大多数情况下,如果文件句柄是通过 SMB 打开的,则文件句柄会在其他应用程序(例如资源管理器甚至系统进程)中打开。
【解决方案2】:

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


由于在调用std::terminate() 之前是否展开堆栈是实现定义的,因此我有时会add code to generate a backtrace 以定位未捕获的异常1

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 感谢您的赞赏。但是……这不是没有意义的。避免终止处理程序是一个好习惯。
    • 很清楚(至少对我而言)OP 已经明白这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-24
    • 1970-01-01
    • 2013-07-26
    相关资源
    最近更新 更多