Search

7.11 — Halts (exiting your program early)

The last category of flow control statement we’ll cover is the halt. A halt is a flow control statement that terminates the program. In C++, halts are implemented as functions (rather than keywords), so our halt statements will be function calls.

Let’s take a brief detour, and recap what happens when a program exits normally. When the main() function returns (either by reaching the end of the function, or via a return statement), a number of different things happen.

First, because we’re leaving the function, all local variables and function parameters are destroyed (as per usual).

Next, a special function called std::exit() is called, with the return value from main() (the status code) passed in as an argument. So what is std::exit()?

The std::exit() function

std::exit() is a function that causes the program to terminate normally. Normal termination means the program has exited in an expected way. Note that the term normal termination does not imply anything about whether the program was successful (that’s what the status code is for). For example, let’s say you were writing a program where you expected the user to type in a filename to process. If the user typed in an invalid filename, your program would probably return a non-zero status code to indicate the failure state, but it would still have a normal termination.

std::exit() performs a number of cleanup function. First, objects with static storage duration are destroyed. Then some other miscellaneous file cleanup is done if any files were used. Finally, control is returned back to the OS, with the argument passed to std::exit() used as the status code.

Calling std::exit() explicitly

Although std::exit() is called implicitly when function main() ends, std::exit() can also be called explicitly to halt the program before it would normally terminate. When std::exit() is called this way, you will need to include the cstdlib header.

Here is an example of using std::exit() explicitly:

This program prints:

1
cleanup!

Note that the statements after the call to std::exit() never execute because the program has already terminated.

Although in the program above we call std::exit() from function main(), std::exit() can be called from any function to terminate the program at that point.

One important note about calling std::exit() explicitly: std::exit() does not clean up any local variables (either in the current function, or in functions up the call stack). Because of this, it’s generally better to avoid calling std::exit().

Warning

The std::exit() function does not clean up local variables in the current function or up the call stack.

std::atexit

Because std::exit() terminates the program immediately, you may want to manually do some cleanup (in the above example, we manually called function cleanup()) before terminating. Remembering to manually call a cleanup function before calling every call to exit() adds burden to the programmer.

To assist with this, C++ offers the std::atexit() function, which allows you to specify a function that will automatically be called on program termination via std:exit().

This program has the same output as the prior example:

1
cleanup!

So why would you want to do this? It allows you to specify a cleanup function in one place (probably in main) and then not have to worry about remembering to call that function explicitly before calling std::exit().

A few notes here about std::atexit() and the cleanup function: First, because std::exit() is called implicitly when main() terminates, this will invoke any functions registered by std::atexit() if the program exits that way. Second, the function being registered must take no parameters and have no return value. Finally, you can register multiple cleanup functions using std::atexit() if you want, and they will be called in reverse order of registration (the last one registered will be called first).

For advanced readers

In multi-threaded programs, calling std::exit() can cause your program to crash (because the thread calling std::exit() will cleanup static objects that may still be accessed by other threads). For this reason, C++ has introduced another pair of functions that work similarly to std::exit() and std::atexit() called std::quick_exit() and std::at_quick_exit(). std::quick_exit() terminates the program normally, but does not clean up static objects, and may or may not do other types of cleanup. std::at_quick_exit() performs the same role as std::atexit() for programs terminated with std::quick_exit().

std::abort and std::terminate

C++ contains two other halt-related functions.

The std::abort() function causes your program to terminate abnormally. Abnormal termination means the program had some kind of unusual runtime error and the program couldn’t continue to run. For example, trying to divide by 0 will result in an abnormal termination. std::abort() does not do any cleanup.

We will see cases later in this chapter (7.17 -- Assert and static_assert) where std::abort is called implicitly.

The std::terminate() function is typically used in conjunction with exceptions (we’ll cover exceptions in a later chapter). Although std::terminate can be called explicitly, it is more often called implicitly when an exception isn’t handled (and in a few other exception-related cases). By default, std::terminate() calls std::abort().

When should you use a halt?

The short answer is “almost never”. In C++, destroying local objects is an important part of C++ (particularly when we get into classes), and none of the above-mentioned functions clean up local variables. Exceptions are a better and safer mechanism for handling error cases.

Best practice

Only use a halt if there is no safe way to return normally from the main function. If you haven’t disabled exceptions, prefer using exceptions for handling errors safely.


7.12 -- Introduction to testing your code
Index
7.10 -- Break and continue

15 comments to 7.11 — Halts (exiting your program early)

  • James C

    Rule at bottom should be a best practice

  • Andrus

    Reading the chapter I was wondering: "So what that it doesn't clean up?" and I was waiting for a explanation why the cleanup is needed and useful. Fortunately the few comments below clarified it. Might be good to add those examples to the chapter as well.

  • Tobito

    Can you add the code how to do clean up the local variabel?

  • Waldo Lemmer

    Wow, this is probably the messiest part of C++ that I've encountered thus far. Great explanation, though!

    Section "std::abort and std::terminate" ends with a stray "j".

  • J34NP3T3R

    so if the program is terminated explicitly, and doesn't do cleanups.

    what happens to the Global variables ?

    when you say cleanup() as in "code here to do any kind of cleanup required"
    do you mean manually destroy all variables used ? wouldn't that take a lot of work compare to letting C++ destroy them on its own ?

    • nascardriver

      Same thing as if the program crashed. All resources that your program held will remain occupied, unless/until the OS frees them.

      A common example are applications that open a port. If such an application doesn't exit cleanly, and you try to start it again, it will fail to start, because the port is still occupied by the remnants of the previous process. If you wait a minute or two, the OS will likely have noticed that something is wrong and it will have closed the port and it's usable again.

  • Here a question that might sounds silly but "One important note about calling std::exit() explicitly: std::exit() does not clean up any local variables" does that mean the allocated memory given to the program at execute time is not beeing released at the end of the program?(meaning some of the memory still being occupied by them even thought the program is done executing)" .

    • nascardriver

      Yes

      Operating systems typically clean up memory that was left behind, but you shouldn't rely on that. If you can exit by flowing off the end of `main`, do so.

  • Evrik

    Link (13.1 -- Input and output (I/O) streams) does not work

  • Herevei

    Found a mistake, section "std::abort and std::terminate":

    "We will see cases later in this chapter (link id=”5100″) where std::abort is called implicitly."

    Also, another one here, I think:

    "By default, std::terminate() calls std::abort().j"

    Thank you for your amazing course! Have a nice day and happy new year! :)

Leave a Comment

Put all code inside code tags: [code]your code here[/code]