我知道我的析构函数会在正常的栈展开和抛出异常时被调用,但在调用exit()函数时不会被调用。
还有其他情况会导致析构函数不被调用吗?比如SIGINT或SIGSEGV等信号。我猜想对于SIGSEGV,析构函数不会被调用,但对于SIGINT会被调用。如何知道哪些信号会展开堆栈?
还有其他情况会导致析构函数不被调用吗?
我知道我的析构函数会在正常的栈展开和抛出异常时被调用,但在调用exit()函数时不会被调用。
还有其他情况会导致析构函数不被调用吗?比如SIGINT或SIGSEGV等信号。我猜想对于SIGSEGV,析构函数不会被调用,但对于SIGINT会被调用。如何知道哪些信号会展开堆栈?
还有其他情况会导致析构函数不被调用吗?
struct X { X() try : x_(42) {} catch (...) {} private: int x_; };
实际上,您可以将其用于任何函数,例如 void foo() try {} catch (...) {}
但是一些重要的编译器(如VS2008,不知道是否已在后续版本中修复)会 choke on it。尽管如此,有关智能指针的建议仍然有效。 - Fabio Fracassitry
在 GOTW #66 中有详细说明(今天刚好向同事指出...巧合...)。 - Matthieu M.如果一个函数或方法有throws规范,并且抛出的内容不在规范范围内,则默认行为是立即退出。堆栈不会被展开,析构函数也不会被调用。
POSIX信号是特定于操作系统的构造,没有C++对象作用域的概念。通常情况下,你不能对信号做任何事情,除了可能捕获它,设置一个全局标志变量,然后在信号处理程序退出后在你的C++代码中处理它。
近期版本的GCC允许您在同步信号处理程序中抛出异常,这确实会导致预期的展开和销毁过程。但这非常依赖操作系统和编译器。
基本上有两种情况会调用析构函数:在函数末尾(或异常处)的堆栈展开时,如果有人(或引用计数器)调用delete。
一个特殊的情况是在静态对象中发现的-它们通过at_exit在程序结束时被销毁,但这仍然是第二种情况。
离开at_exit的信号可能取决于,kill -9将立即终止进程,其他信号将告诉它退出,但具体如何取决于信号回调。
delete
时才会调用析构函数。因此,对于从未调用delete
的动态对象,析构函数不会被调用(无论是因为内存泄漏使其不可能,还是由于疏忽)。 - Marc van Leeuwen