我知道我的析构函数在堆栈的正常展开时被调用,并且在抛出异常时调用,但是在调用exit()时不会。
还有其他情况我的析构函数不会被调用吗?信号如SIGINT或SIGSEGV怎么样?我认为对于SIGSEGV,它们不会被调用,但对于SIGNINT它们是,我怎么知道哪些信号将展开堆栈?
是否有其他情况不会被召唤?
答案 0 :(得分:47)
是否还有其他情况导致他们的[析构函数]不会被调用?
答案 1 :(得分:7)
C ++标准没有说明必须如何处理特定信号 - 许多实现可能不支持SIGINT
等。如果exit()
或abort()
或{{1}将不会调用析构函数}} 叫做。
编辑:我刚刚通过C ++标准进行了快速搜索,但是我找不到任何指定信号如何与对象生命周期交互的东西 - 也许是一个比我有更好标准的人找东西?
进一步修改:在回答其他问题时,我在标准中发现了这一点:
退出范围时(但是 完成),析构函数(12.4)是 要求所有构造的对象 具有自动存储持续时间 (3.7.2)(命名对象或临时对象) 在该范围内声明的,在 他们的相反顺序 宣言。
所以似乎必须在收到信号时调用析构函数。
答案 2 :(得分:3)
信号本身不会影响当前线程的执行,从而影响析构函数的调用,因为它是一个具有自己堆栈的不同执行上下文,你的对象不存在的地方。这就像一个中断:它在执行上下文之外的某个地方处理,如果处理,控制权将返回给你的程序。
与多线程相同,C ++ 语言不知道信号的概念。这两者完全相互正交,由两个不相关的标准规定。它们如何相互作用取决于实施,只要它不违反任何标准。
作为旁注,另一种情况是,当构造函数抛出异常时,不会调用对象的析构函数。不过,成员的破坏者仍将被召唤。
答案 3 :(得分:3)
他们不会被调用的另一种情况是你使用多态并且没有使你的基础析构函数成为虚拟。
答案 4 :(得分:2)
abort
终止程序而不对自动或静态存储持续时间的对象执行析构函数。对于其他情况,您应该阅读特定于实现的文档。
答案 5 :(得分:2)
如果函数或方法具有throws规范,并抛出规范未涵盖的内容,则默认行为是立即退出。堆栈没有展开,也没有调用析构函数。
POSIX信号是特定于操作系统的构造,并且没有C ++对象范围的概念。通常你不能对信号做任何事情,除了可能,捕获它,设置一个全局标志变量,然后在信号处理程序退出后在你的C ++代码中处理它。
最新版本的GCC允许您从同步信号处理程序中抛出异常,这会导致预期的展开和销毁过程。这是非常操作系统和编译器,但
答案 6 :(得分:2)
这里有很多答案,但仍然不完整!
我发现了另一个没有执行析构函数的情况。当跨越库边界捕获异常时,总会发生这种情况。
在此处查看更多详情:
Destructors not executed (no stack unwinding) when exception is thrown
答案 7 :(得分:1)
基本上有两种情况,其中调用析构函数:在函数结束时(或异常情况下)堆栈展开,如果有人(或引用计数器)调用delete。
在静态对象中可以找到一种特殊情况 - 它们在程序结束时通过at_exit被破坏,但这仍然是第二种情况。
at_exit通过哪个信号可能取决于,kill -9会立即终止进程,其他信号会告诉它退出但是究竟是如何依赖于信号回调。