Is destructor called if SIGINT or SIGSTP issued?

No, by default, most signals cause an immediate, abnormal exit of your program.

However, you can easily change the default behavior for most signals.

This code shows how to make a signal exit your program normally, including calling all the usual destructors:

#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <cstring>
#include <atomic>

std::atomic<bool> quit(false);    // signal flag

void got_signal(int)
{
    // Signal handler function.
    // Set the flag and return.
    // Never do real work inside this function.
    // See also: man 7 signal-safety
    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;
}

If you run this program and press control-C, you should see the word “destructor” printed.

Be aware that your signal handler function (got_signal) should rarely do any work, other than setting a flag and returning quietly, unless you really know what you are doing. See also: https://man7.org/linux/man-pages/man7/signal-safety.7.html

Most signals are catchable as shown above, but not SIGKILL, you have no control over it because SIGKILL is a last-ditch method for killing a runaway process, and not SIGSTOP which allows a user to freeze a process cold. Note that you can catch SIGTSTP (control-Z) if desired, but you don’t need to if your only interest in signals is destructor behavior, because eventually after a control-Z the process will be woken up, will continue running, and will exit normally with all the destructors in effect.

Leave a Comment