【发布时间】:2011-05-14 02:17:54
【问题描述】:
我有一个带有用户定义析构函数的类。如果该类最初是实例化的,然后在程序运行时发出 SIGINT(在 unix 中使用 CTRL+C),会调用析构函数吗? SIGSTP(unix 中的 CTRL + Z)的行为是什么?
【问题讨论】:
标签: c++ destructor sigint
我有一个带有用户定义析构函数的类。如果该类最初是实例化的,然后在程序运行时发出 SIGINT(在 unix 中使用 CTRL+C),会调用析构函数吗? SIGSTP(unix 中的 CTRL + Z)的行为是什么?
【问题讨论】:
标签: c++ destructor sigint
不,默认情况下,大多数信号都会导致程序立即异常退出。
但是,您可以轻松更改大多数信号的默认行为。
这段代码展示了如何让信号正常退出程序,包括调用所有常用的析构函数:
#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <cstring>
#include <atomic>
std::atomic<bool> quit(false); // signal flag
void got_signal(int)
{
quit.store(true);
}
class Foo
{
public:
~Foo() { std::cout << "destructor\n"; }
};
int main(void)
{
struct sigaction sa;
memset( &sa, 0, sizeof(sa) );
sa.sa_handler = got_signal;
sigfillset(&sa.sa_mask);
sigaction(SIGINT,&sa,NULL);
Foo foo; // needs destruction before exit
while (true)
{
// do real work here...
sleep(1);
if( quit.load() ) break; // exit normally after SIGINT
}
return 0;
}
如果你运行这个程序并按下 control-C,你应该会看到打印出的单词“destructor”。请注意,您的信号处理函数 (got_signal) 应该很少做任何工作,除了设置标志并悄悄返回,除非您真的知道自己在做什么。
如上所示,大多数信号都是可捕获的,但不是 SIGKILL,您无法控制它,因为 SIGKILL 是杀死失控进程的最后手段,而不是允许用户冻结进程的 SIGSTOP。请注意,如果需要,您可以捕获 SIGTSTP (control-Z),但如果您对信号的唯一兴趣是析构函数行为,则不需要这样做,因为最终在 control-Z 之后,进程将被唤醒,将继续运行,并且将在所有析构函数生效的情况下正常退出。
【讨论】:
quit 的正确类型应该是volatile std::sig_atomic_t。为此目的使用 bool 是 UB。
use of deleted functionquit = false 行。您必须使用quit(false) 而不是quit = false。还值得注意的是,此代码不适用于 Windows;你必须使用SetConsoleCtrlHandler()。
如果您自己不处理这些信号,那么不,不会调用析构函数。但是,操作系统将在程序终止时回收您的程序使用的所有资源。
如果您希望自己处理信号,请考虑查看sigaction 标准库函数。
【讨论】:
让我们试试吧:
#include <stdio.h>
#include <unistd.h>
class Foo {
public:
Foo() {};
~Foo() { printf("Yay!\n"); }
} bar;
int main(int argc, char **argv) {
sleep(5);
}
然后:
$ g++ -o test ./test.cc
$ ./test
^C
$ ./test
Yay!
所以恐怕不行,你必须抓住它。
对于SIGSTOP,它无法被捕获,并暂停该过程,直到发送SIGCONT。
【讨论】: