Why Is Using Exit() Considered Bad

Why is using exit() considered bad?

Just blindly calling exit() somewhere in your program is considered bad for a simple reason:

It does not properly shutdown other threads (they just get terminated), it does not properly flush all buffers (stdio files are flushed) and guarantee a consistent and valid state of permanent/shared resources (files/shared memory/other ways to communicate).

Still, if you can guarantee that no thread is running which might interfere (by being killed holding a lock or such), and all buffers which need it will be flushed by exit(), that's a valid way to achieve a faster shutdown.

Much modern software is programmed for even faster shutdown:

It is crash-tolerant, in that at nearly every time, just shutting down using e.g. _Exit() (not even calling atexit or at_quick_exit registered hooks) is ok. That is vastly faster than an ordered shutdown in most cases (Windows user interface resources should be destroyed first if possible, because they are an exception).

For further reading: Crash-only software (PDF!)

Crash-only programs crash safely and recover quickly.
There is only one way to stop such software - by crashing
it - and only one way to bring it up - by initiating recovery.
Crash-only systems are built from crash-only components,
and the use of transparent component-level retries
hides intra-system component crashes from end users. In
this paper we advocate a crash-only design for Internet systems,
showing that it can lead to more reliable, predictable
code and faster, more effective recovery. We present ideas
on how to build such crash-only Internet services, taking
successful techniques to their logical extreme.

Should we use exit() in C?

Rather than abort(), the exit() function in C is considered to be a "graceful" exit.

From C11 (N1570) 7.22.4.4/p2 The exit function (emphasis mine):

The exit function causes normal program termination to occur.

The Standard also says in 7.22.4.4/p4 that:

Next, all open streams with unwritten buffered data are flushed, all
open streams are closed, and all files created by the tmpfile function
are removed.

It is also worth looking at 7.21.3/p5 Files:

If the main function returns to its original caller, or if the exit
function is called, all open files are closed (hence all output
streams are flushed) before program termination. Other paths to
program termination, such as calling the abort function, need not
close all files properly.

However, as mentioned in comments below you can't assume that it will cover every other resource, so you may need to resort to atexit() and define callbacks for their release individually. In fact it is exactly what atexit() is intended to do, as it says in 7.22.4.2/p2 The atexit function:

The atexit function registers the function pointed to by func, to be
called without arguments at normal program termination.

Notably, the C standard does not say precisely what should happen to objects of allocated storage duration (i.e. malloc()), thus requiring you be aware of how it is done on particular implementation. For modern, host-oriented OS it is likely that the system will take care of it, but still you might want to handle this by yourself in order to silence memory debuggers such as Valgrind.

When is it better to use exit() vs exceptions in c++?

exit() is fine for small programs. For larger programs, there are several problems with it. First, not all errors should terminate a program - often it can recover.

The 2nd problem: even if you want to terminate, it is difficult to write a single clean_up() function that would take care of all resources allocated in various parts of the program. This what RAII in C++ is for. exit() is incompatible with RAII as it does not call destructors, except for global or static objects.

The 3rd problem: at the point of error detection, you often cannot construct an error message meaningful to the end user, but it is possible to construct such error message when an exception is caught.

Usually, the dilemma is different: the alternative to exceptions is using return codes to indicate errors. There are multiple trade-offs between exceptions and return codes, and hundreds of articles are devoted to this topic. It is too large to analyze within this answer.

Should I end my PHP script with exit or exit;?

exit, exit;, exit(), and exit(); are exactly the same, but the fact is that you should not end your script with an exit() call, it's just bad practice (but it works).

EDIT

Clarifying why i said it's "bad practice", it's not about the functionality of "exit" itself, it's OK to halt the script execution if something bad happens, but the concept of "something bad" is really wide. In general, even if some unwanted condition occurs, the normal execution flow should reach to the end of the file. Just consider this example:

...some init stuff...
if (!user_is_authenticated) {
...print some nasty message...
exit();
}
...continue with normal stuff...

A better approach would be:

...some init stuff...
if (user_is_authenticated) {
...continue with normal stuff...
}
else {
...print some nasty message...
}

What's the difference? The difference is that in the second version you don't need to use exit(), which means if one day you need to do something after BOTH the "normal" and "unwanted" execution flows you can just add it at the end of the file.

It's more or less the same argument about why you should NOT use "return" in function bodies except at the end of the function..

Python exit commands - why so many and when should each be used?

The functions* quit(), exit(), and sys.exit() function in the same way: they raise the SystemExit exception. So there is no real difference, except that sys.exit() is always available but exit() and quit() are only available if the site module is imported (docs).

The os._exit() function is special, it exits immediately without calling any cleanup functions (it doesn't flush buffers, for example). This is designed for highly specialized use cases... basically, only in the child after an os.fork() call.

Conclusion

  • Use exit() or quit() in the REPL.

  • Use sys.exit() in scripts, or raise SystemExit() if you prefer.

  • Use os._exit() for child processes to exit after a call to os.fork().

All of these can be called without arguments, or you can specify the exit status, e.g., exit(1) or raise SystemExit(1) to exit with status 1. Note that portable programs are limited to exit status codes in the range 0-255, if you raise SystemExit(256) on many systems this will get truncated and your process will actually exit with status 0.

Footnotes

* Actually, quit() and exit() are callable instance objects, but I think it's okay to call them functions.

Is it a bad practice to use break in a for loop?

Lots of answers here, but I haven't seen this mentioned yet:

Most of the "dangers" associated with using break or continue in a for loop are negated if you write tidy, easily-readable loops. If the body of your loop spans several screen lengths and has multiple nested sub-blocks, yes, you could easily forget that some code won't be executed after the break. If, however, the loop is short and to the point, the purpose of the break statement should be obvious.

If a loop is getting too big, use one or more well-named function calls within the loop instead. The only real reason to avoid doing so is for processing bottlenecks.

Is it bad practice to use break to exit a loop in Java?

Good lord no. Sometimes there is a possibility that something can occur in the loop that satisfies the overall requirement, without satisfying the logical loop condition. In that case, break is used, to stop you cycling around a loop pointlessly.

Example

String item;

for(int x = 0; x < 10; x++)
{
// Linear search.
if(array[x].equals("Item I am looking for"))
{
//you've found the item. Let's stop.
item = array[x];
break;
}
}

What makes more sense in this example. Continue looping to 10 every time, even after you've found it, or loop until you find the item and stop? Or to put it into real world terms; when you find your keys, do you keep looking?

Edit in response to comment

Why not set x to 11 to break the loop? It's pointless. We've got break! Unless your code is making the assumption that x is definitely larger than 10 later on (and it probably shouldn't be) then you're fine just using break.

Edit for the sake of completeness

There are definitely other ways to simulate break. For example, adding extra logic to your termination condition in your loop. Saying that it is either loop pointlessly or use break isn't fair. As pointed out, a while loop can often achieve similar functionality. For example, following the above example..

while(x < 10 && item == null)
{
if(array[x].equals("Item I am looking for"))
{
item = array[x];
}

x++;
}

Using break simply means you can achieve this functionality with a for loop. It also means you don't have to keep adding in conditions into your termination logic, whenever you want the loop to behave differently. For example.

for(int x = 0; x < 10; x++)
{
if(array[x].equals("Something that will make me want to cancel"))
{
break;
}
else if(array[x].equals("Something else that will make me want to cancel"))
{
break;
}
else if(array[x].equals("This is what I want"))
{
item = array[x];
}
}

Rather than a while loop with a termination condition that looks like this:

while(x < 10 && !array[x].equals("Something that will make me want to cancel") && 
!array[x].equals("Something else that will make me want to cancel"))

atexit considered harmful?

The main reason I would avoid using atexit in libraries is that any use of it involves global state. A good library should avoid having global state.

However, there are also other technical reasons:

  1. Implementations are only required to support a small number (32, I think) of atexit handlers. After that, it's possible that all calls to atexit fail, or that they succeed or fail depending on resource availability. Thus, you have to deal with what to do if you can't register your atexit handler, and there might not be any good way to proceed.

  2. Interaction of atexit with dlopen or other methods of loading libraries dynamically is not defined. A library which has registered atexit handlers cannot safely be unloaded, and the ways different implementations deal with this situation can vary.

  3. Poorly written atexit handlers could have interactions with one another, or just bad behaviors, that prevent the program from properly exiting. For instance, if an atexit handler attempts to obtain a lock that's held in another thread and that can't be released due to the state at the time exit was called.



Related Topics



Leave a reply



Submit