Abhishek Garg
Abhishek Garg

Reputation: 308

Signal Handling to Ensure Destructors are Called in C++

I have a class with constructor and destructor. Let's call that class as Student.

Suppose there is some code

{
    //some code
    Student student;
    //signal , may be ctrl+c or any other signal

}

What I want is when signal is thrown, I still want the destructor of student object to be called.

I have some basics knowledge of signals but I don't know how to do this.

I know this can be specific to o/s; I am trying for Linux.

Upvotes: 0

Views: 1495

Answers (2)

Mirko
Mirko

Reputation: 1083

You CAN according to the standard also call std::quick_exit. You need to register some cleanup function with std::at_quick_exit. As an example:

#include <cstdlib>
#include <cstring>
#include <iostream>
#include <set>
#include <signal.h>
#include <unistd.h>

using namespace std;

class K
{
public:
    K(const char* _name)
    : name(_name)
    { cout << "K() for " << name << endl; registered.emplace(this); }
    ~K()
    { cout << "~K() for " << name << endl; registered.erase(this); }

    static void cleanup()
    {
        for (auto i: registered) {
            i->~K();
        }
    }

private:
    const char* name= nullptr;
    static set<K*> registered;
};
set<K*> K::registered;

extern "C"
void signalHandler(int sig, siginfo_t* info, void* context)
{
    if (sig == SIGKILL || sig == SIGTERM || sig == SIGINT) {
        quick_exit(1);
    }
    return;
}

K k1("global k1");

int main(int argc, const char* argv[])
{
    struct sigaction act;
    memset(&act, 0, sizeof(act));
    act.sa_sigaction= signalHandler;
    act.sa_flags= SA_SIGINFO;
    sigemptyset(&act.sa_mask);
    for (int i= 0; i < 64; i++) {
        sigaction(i, &act, nullptr);
    }

    K k2("local k2");
    at_quick_exit(K::cleanup);
    for (int i= 0; i < 10; i++) {
        cout << "." << flush;
        sleep(1);
    }
    cout << "Normal exit" << endl;

    return 0;
}

Upvotes: 0

n. m. could be an AI
n. m. could be an AI

Reputation: 120079

This cannot be done easily in C++.

You need to handle the signal. The handler needs to inform the program about the event. The program needs to react by shutting down cleanly (this is most often done by throwing an exception; naturally your program must exercise exception safety for this to work).

The problem lies in the inform—react sequence. There is no good way of doing this. According to the standard, the only thing a signal handker is permitted to do is to set a global variable of type sig_atomic_t and return. Consequently, the program must check the value of that variable periodically and react when its value is changed.

Some operating systems may allow more things that are safe to do in an exception handler. Throwing a C++ exception, however, isn't normally one of those things. Signals are asynchronous in nature. If one is delivered when an object is in the middle of construction, throwing an exception is likely to leave its state inconsistent.

So just about the only way is to insert checks everywhere in the program, or perhaps if it has a centralised IO or event loop, insert a check there.

Upvotes: 1

Related Questions