How do you run a function on exit in C++

前端 未结 4 1816
温柔的废话
温柔的废话 2021-02-05 10:27

I have a function that I want to run whenever my program exits:

void foo() {
  std::cout<< \"Exiting\" << std::endl;
}

How do I reg

相关标签:
4条回答
  • 2021-02-05 10:39

    You can use the aptly named std::atexit function in the cstdlib header:

    #include <cstdlib>
    
    void exiting() {
        std::cout << "Exiting";
    }
    
    int main() {
        std::atexit(exiting);
    }
    

    The system will maintain a stack of functions registered with atexit and call them each in the reverse order of their registration when either the exit function is called, or the program returns from main. You can register at least 32 functions this way.

    0 讨论(0)
  • 2021-02-05 10:40

    The only way (in Unix and Unix-like operating systems) to regain control after a process exits is to wait(2) for it. Short of a powerfail, kernel panic, or forced reboot, this should work:

    #include <sys/types.h>
    #include <sys/wait.h>
    #include <iostream>
    
    int AtExit() {
        pid_t pid = fork();
        if(pid < 0) return pid;
        if(pid == 0) return pid;
        pid = waitpid(pid, 0, 0);
        return pid;
    }
    
    int main () {
      if(AtExit()) {
        std::cout << "Exiting\n";
        return 0;
      }
    
      std::cout << 7 << "\n";
    }
    
    0 讨论(0)
  • 2021-02-05 10:41

    I am answering as a Linux user, but all of this should apply to windows.

    I had this similar question, so hopefully I can sum up previous answers and add my two cents.

    Signals and abort(): ^C and ^Z can be "intercepted" to call your function before exiting, presumably with exit(). Signals SIGQUIT AKA ^\ and SIGKILL which has no key stroke cannot be intercepted. Here's an example for using the csignal header and a C++ lambda.

    #include <iostream>
    #include <csignal>
    #include <cstdlib>
    
    using namespace std;
    
    int main()
    {
        //signal requires lam take an int parameter
        //this parameter is equal to the signals value
        auto lam = 
          [] (int i) { cout << "aborting" << endl; exit(0); };
    
        //^C
        signal(SIGINT, lam);
        //abort()
        signal(SIGABRT, lam);
        //sent by "kill" command
        signal(SIGTERM, lam);
        //^Z
        signal(SIGTSTP, lam);
    
    
        while(1)
        {
        }
    
        return 0;
    }
    

    Exit: Since I used exit() in my examples above, care must be taken here. If the function being run is a clean-up function that only needs to run once, perhaps a static variable has_run could be used. Or in the example above, raise() a signal that you can't intercept. But those tend to come with core dumps which just feels dirty. Your choice, here. An example follows

    #include <cstdlib>
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        //called with no parameters
        auto lam = [] () { cout << "at exit"; };
    
        atexit(lam);
    
        return 0;
    }
    

    Take note that c++11 added a quick_exit which has an accompanying at_quick_exit which act the same as above. But with quick_exit no clean up tasks are performed. In contrast, with exit object destructors are called and C streams are closed, with only automatic storage variables not getting cleaned up.

    0 讨论(0)
  • 2021-02-05 10:43

    You could put it in the destructor of a class with a global instance.

    class SomeGlobalStuff {
        ~SomeGlobalStuff() {
              foo();
        }
        static SomeGlobalStuff instance;
    };
    // putting this in a single compilation unit.
    SomeGlobalStuff SomeGlobalStuff::instance instance;
    

    But like any other method, you have to remember that you cannot use any data if you cannot garantee that it still exists. Deallocation of global objects is done in a arbitrary order, so basically, you cannot use std::cout in the foo() function. atexit() is worse in this regard, because whether it executes before or after destruction of global objects depends on the compiler and compiler options.

    And anyway, you still have to handle signals correctly. You have to choose which signals to handle and which to not handle (you most likely don't want to handle SIGSEGV). You cannot escape signal handling. And remember that signals may interrupt your program at any time (unless masked) so your data structures might be in a arbitrary state, in the middle of an update.

    0 讨论(0)
提交回复
热议问题