Ibrahim Ipek Ibrahim Ipek - 4 months ago 16
C++ Question

what is the difference between exit and std::exit in C++?

what is the difference between

exit
and
std::exit
in C++? I have researched it but i couldn't find anything.

What is the difference between these two codes:

1:

if(SDL_Init(SDL_INIT_EVERYTHING) != 0)
{
std::cout << "Error: Can't initialize the SDL \n";
exit(EXIT_FAILURE);
}


2:

if(SDL_Init(SDL_INIT_EVERYTHING) != 0)
{
std::cout << "Error: Can't initialize the SDL \n";
std::exit(EXIT_FAILURE);
}

Answer

They're two names for the same function that does the same things.

Note, however, that in C++ std::exit/exit (regardless of how you get to its name) does have some behavior that's not specified for the exit in the C library. In particular,

  1. exit first destroys all objects with thread storage duration that are associated with the current thread.
  2. Objects with static storage duration are destroyed, and any functions registered with atexit are invoked.
    • If one of these throws an exception that isn't caught, terminate is invoked.
  3. After that we get the normal C behavior:
    • Open C streams are flushed if they have unwritten data, then they're closed.
    • Files created by calling tmpfile are removed.
    • Control is returned to the host environment, returning success or failure depending on the value passed in the call to exit (0 or EXIT_SUCCESS => success, EXIT_FAILURE => failure, anything else is implementation defined).

Note in particular that local objects are not destroyed by any call to exit.

That means, in effect, that you should really forget all of the above, and simply never call exit/std::exit from C++ code. While the committee apparently feels that compatibility with C code is a strong enough motivation that they need to leave it in the standard, you certainly don't need to use it--and under almost any reasonably normal circumstances, you shouldn't. Destroying local objects on exit from a scope is an important enough part of C++ that a function like exit that removes this guarantee leads to almost nothing but headaches.

If you need behavior vaguely similar to that of exit, you normally want to do something like this:

struct my_exit : public std::exception { 
    int value;
    my_exit(int value) : value(value) {}
};

int main() { 
    try {
        // do normal stuff
    }

    catch(my_exit const &e) {
        return e.value;
    }
}

Then in the rest of the code where you would otherwise have called exit, you instead throw my_exit(whatever_value);. This way, all the local variables will be destroyed (i.e., stack unwinding will happen) and then you'll do a normal exit to the environment.