C++中在异常终止或退出时保证被调用的函数

6

C++中哪个函数保证在突然终止或退出时被调用,可以执行清理活动..


7
从技术上讲,没有什么是“保证”的——如果你没有UPS而电源中断了,或者处理器的电源供应出现故障,或者时钟振荡器出现故障(这些事件都很少见但可能发生),那么CPU将停止工作。 - Jason S
8个回答

10

根据"abrupt termination"的具体含义,有几种不同的选择:

  • 正常终止(从main返回或调用exit())时将调用全局析构函数。
  • atexit()注册一个函数,在正常终止时被调用。
  • std::set_terminate注册一个函数,当抛出但未捕获异常或因其他原因需要"终止异常处理"时调用。
  • sigaction()注册函数,在程序接收到信号时调用,其中许多信号通常会突然终止您的程序。 当程序处于内部不一致状态时,可能会调用信号处理程序,因此它们的功能非常有限。例如,它们不能执行任何可能分配内存的操作。此外,此API在Windows上不可用;有相应的替代品,但我不熟悉它们。
请注意,所有常见的操作系统都提供了至少一种突然终止程序的方式,这种方式无法从代码中拦截。例如,Unix有信号9 (SIGKILL),你无法为其注册处理程序。这是一种特性,而不是错误。你作为用户需要一种方法来关闭一个进程,即使它已经尽力使自己无法被摧毁。此外,当用户的宠物兔子咬断电脑的电源线时,任何代码都无法保护您的进程。因此,设计程序以从崩溃中恢复可能是更好的选择,而不是在崩溃发生时尝试清理。有关此内容,请参阅 "crash-only design" 的文章。

2

在这里阅读关于atexit的内容:http://www.cplusplus.com/reference/clibrary/cstdlib/atexit/。然而,并不是所有情况下都会调用它(例如,调用abort时不会触发您使用atexit注册的函数)。

您可以实现自己的信号处理程序,将所有信号传递到那里,并为每个信号执行任何操作。


这是与OP要求最接近的答案。无法保证退出处理程序将被调用。程序可能会触发无法捕获或未被捕获的信号;程序员可以调用 abort() 强制程序异常退出,或者 _Exit() 强制程序正常退出但绕过退出处理程序。但是,从主函数返回或调用 exit() 将运行退出处理程序。 - David Hammen

1

这是导致突然终止的原因,而不是被它调用。 - littleadv
@David 其中一位无法阅读。他正在询问如何处理由异常引起的程序退出。 - Šimon Tóth
@Let - 在哪里?问题中甚至没有出现“异常”这个词。他正在寻找一种在任何类型的终止(突然或正常退出)时被调用的方法。至少这是我从问题中读到的。 - littleadv
@littleadv 它被标记为异常处理。 - Šimon Tóth

1
int main()
{
    try
    {
        // all your code here
    }
    catch(...)
    {
        // cleanup
    }
    return 0;
}

显然不是这样的,因为set_terminate的文档指出:“终止处理程序函数是在某些情况下必须放弃异常处理过程时自动调用的函数。” - Jason S
这并不涵盖所有内容,但仍然是一个很好的基准。 - zwol

0
你在什么环境下工作?你所说的“abrupt”是指Ctrl+C还是kill -9信号?
在Unix/Linux上,你可以屏蔽一些信号并提供处理程序,但据我所知,你无法屏蔽所有信号(9是一个无法屏蔽的信号示例,它会突然终止你的进程)。
甚至可能存在更低级别的操作系统覆盖,但我不熟悉那方面的内容。

0

我不是专家,只知道一些关于C++的东西,但我知道你可以在Unix和C中创建句柄来检测具体信号,然后执行函数,最后通过“exit(n)”终止程序。

你可以使用signalsigaction来实现,但问题是你只能用这种方法处理除SIGKILL或SIGSTOP之外的任何信号。


0

没有一个函数能够捕获所有的情况并且在所有的平台上都能运行。如果你需要在Windows上使用,你将必须处理SEH(Structured exception handling)异常。你需要定义和设置各种场景下的处理程序(SEH、C++异常、SIGABRT、Terminate等),执行共同的清理代码。查看zack在此处有关处理SIGABRT信号的回复。

对于SEH,你可以添加一个SE转换器来处理SE异常,并将它们转换为C++异常,请参考_set_se_translator以获取有关如何处理SEH异常的更多信息。

你可以参考设置terminate处理程序的文档设置unexpected处理程序的好参考

你将不得不编写自己的处理程序来处理每个场景。

最后,我建议使用一些现有的库来实现这个目的,我喜欢crashrprt

我正在使用Windows系统。问题的目的是进行某种清理活动,我希望以这样的方式进行设置,无论程序为何以及从何处退出(正常或崩溃),都能够完成该操作。 - NoName

0

你熟悉信号处理吗?我建议你先学习它,然后再回来提出相关问题。看起来有几个人已经提到了它,但这是一个很好的资源可以参考:

http://www.gnu.org/s/hello/manual/libc/Signal-Handling.html

编写自己的信号处理程序可以让您确定在捕获特定信号时要执行的操作。正如所述,有些信号无法被覆盖,这是有充分理由的。您不想让某人覆盖 kill -9,仅仅因为可能会创建一个不可能终止的程序。然而,像直接 kill 信号或者 ctrl-c、ctrl-d 等信号可以被捕获并按照您选择的方式进行处理。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接