The standard way to end a C++ program is by returning from main() with return 0; for normal exit, or using exit() or abort() as needed.
Knowing how to end program in C++ correctly matters for resource cleanup, exit status signaling, and avoiding undefined behavior. The language provides four distinct termination paths, each designed for a specific situation. This article covers return, exit(), abort(), and terminate() — when to use them, what they do, and which common pitfalls to avoid.
Ending a C++ Program: The Four Standard Methods
C++ gives you four official ways to stop program execution. The choice depends on where you are in the code and whether the stop is normal or abnormal. The following table compares each method at a glance.
| Method | How to Call | Cleanup Behavior | Best Use Case |
|---|---|---|---|
return from main() |
return 0; or return nonzero; |
All local and global objects destroyed normally | Normal exit from within main() |
std::exit() (or exit()) |
std::exit(exit_code); from anywhere |
Registered atexit handlers run; automatic storage objects NOT destroyed |
Early exit, outside main(), when you still want some cleanup |
std::abort() (or abort()) |
std::abort(); from anywhere |
Immediate abnormal termination; no cleanup | Fatal error, crash, or forced stop when cleanup is unsafe |
std::terminate() |
Called automatically by runtime or via std::terminate(); |
Invokes current terminate_handler (default calls abort()) |
Unhandled exceptions or exception-handling failure |
Return 0: The Preferred Normal Exit
Returning from main() is the cleanest, most idiomatic way to end a C++ program. Place a return statement at the end of the main function; by convention, return 0; signals success, and a nonzero value indicates failure. The operating system receives this exit code.
This method destroys all local objects and calls destructors for global and static objects. It’s the default route for normal completion. If you do not explicitly return, the C++ standard says that main() implicitly returns 0 — but being explicit is always safer.
Important: Using return inside a non-main function only exits that function, not the whole program. For that, you need one of the other methods.
std::exit(): Terminate from Anywhere
When you need to end the program from a deeply nested function or a helper routine, call std::exit() (declared in <cstdlib>). Pass the exit code as the argument. The function runs any functions registered with atexit(), but does not destroy automatic storage objects — that is, local variables declared in calling functions are not cleaned up.
This makes exit() slightly less controlled than a normal return, but it is still standard and widely used for early exits when you want to close file handles or flush buffers via atexit handlers. Microsoft’s C++ documentation explicitly lists exit as a standard program-termination option.[5]
std::abort(): Immediate Abnormal Stop
Use std::abort() when the program enters an unrecoverable state — a corrupted data structure, a security violation, or a condition where running further could cause data loss. abort() terminates the process instantly without running destructors or cleanup handlers.
This is the same call that the default terminate_handler uses. Because it skips cleanup, it should be reserved for true emergencies. Do not use abort() for standard exit; that will leave resources open and signal to the OS that the program crashed.
std::terminate(): When Exception Handling Fails
You typically never call std::terminate() directly. Instead, the C++ runtime calls it in these situations:
- No
catchhandler matches a thrown exception. - A destructor throws during stack unwinding.
- A constructor or destructor of a static object, or a function registered with
atexit(), throws an unhandled exception.
The default terminate_handler calls abort(). You can replace the handler with your own using std::set_terminate(), but the replacement must still end the program — it cannot return.
Common Mistakes and How to Avoid Them
Even experienced C++ developers occasionally misuse termination functions. The table below lists frequent pitfalls and the correct approach.
| Mistake | What Happens | Correct Approach |
|---|---|---|
Using return 0; in a non-main function to end the program |
Function returns, but program continues running | Use std::exit() from that function, or restructure logic to propagate control back to main() |
Assuming exit() destroys local objects |
Automatic storage objects are not destroyed — potential resource leak | Only use exit() when you know the lack of local cleanup is safe. Prefer returning from main() if possible. |
Calling abort() for a routine early exit |
Program crashes with no cleanup — misleading for users and tools | Reserve abort() for truly fatal conditions; use exit() or return for normal stops. |
Relying on terminate() as a user-facing exit |
It’s not designed for manual control; behavior is runtime‑dependent and usually calls abort() |
Handle exceptions with try/catch and use return or exit() for intentional termination. |
Which Method Should You Use? A Quick Decision Guide
Here is the practical summary for most C++ programs:
- If you are inside
main()and the program ran successfully →return 0; - If you are inside
main()and an error occurred →return nonzero; - If you are outside
main()and need a normal exit →std::exit(exit_code); - If you encounter a truly unrecoverable error →
std::abort(); - If an exception goes unhandled or the runtime fails to unwind →
std::terminate()is called automatically.
Always prefer return from main() when possible — it gives the most predictable cleanup and the cleanest exit status to the operating system.
References & Sources
- Microsoft. “C++ program termination” Official MSVC documentation covering
return,exit,abort, andatexit.
