In C++, handling errors correctly is essential to ensure program stability and predictability.
Two common mechanisms used for this purpose are std::runtime_error
, which is part of the language's exception system, and std::exit
, which terminates the process immediately.
Although both can be used to signal failures, they have completely different purposes: one focuses on handling and recovery, the other on immediate termination.
In this article, we will see how each one works, show when to apply them, and discuss which approach is more suitable in different development contexts.
std::runtime_error
std::runtime_error
is a standard C++ library exception derived from std::exception
.
It is used to signal runtime errors that prevent the normal continuation of the program.
Usage:
#include <stdexcept>
#include <iostream>
void loadFile(const std::string& path) {
if (path.empty()) {
throw std::runtime_error("Invalid file path");
}
// ...
}
int main() {
try {
loadFile("");
} catch (const std::runtime_error& e) {
std::cerr << "Error: " << e.what() << '\n';
}
}
Characteristics:
- It is thrown with
throw
and handled withtry/catch
. - Allows controlled error propagation, preserving the program state.
- Ensures automatic resource release via stack unwinding (destructors of local objects are called).
- Ideal for recoverable or predictable errors, such as read failure, invalid value, etc.
std::exit
std::exit
(defined in <cstdlib>
) terminates the program immediately, returning a status code to the operating system.
Usage:
#include <cstdlib>
#include <iostream>
int main() {
std::cerr << "Fatal error, terminating.\n";
std::exit(EXIT_FAILURE);
}
Characteristics:
- Does not throw an exception, nor performs stack unwinding.
- Automatic (local) objects do not have their destructors called.
- Static and global objects are still destroyed.
- Ideal for fatal errors or situations where the program state is completely corrupted.
Which to use and when?
Situation | Recommended | Reason |
---|---|---|
Predictable or recoverable error | std::runtime_error |
Allows handling via try/catch and automatic cleanup |
Irrecoverable error (e.g., memory corruption, severe initialization failure) | std::exit |
Terminates immediately and in a controlled manner |
Library or engine code | std::runtime_error |
Gives the caller a chance to react |
Small program or simple utility | std::exit |
Simplicity, no need for exceptions |
- Use
std::runtime_error
when you want to propagate and handle errors within the program logic. - Use
std::exit
only when there is no way to continue — the error is fatal. - In general,
std::runtime_error
is safer and more flexible, as it maintains flow control and ensures proper resource destruction.
It depends on the context.
throw std::runtime_error(...)
Better in most cases.
- Allows handling with
try/catch
, stack unwinding, and destructors are called correctly (RAII). - Used when there is a logical or flow error, and you want to propagate the error.
throw std::runtime_error("Invalid file");
std::exit(1)
Use only if you want to terminate IMMEDIATELY and don't need to release resources.
- Does not perform stack unwinding → destructors are not called.
- Good for
main()
level, tools, or if you really need to abort without exceptions.
std::cerr << "Fatal error\n";
std::exit(1);
Situation | Best Option |
---|---|
Code with RAII/allocated resources | throw std::runtime_error |
In main() or simple tool |
std::exit(1) |
Needs error handling | throw |
Want to terminate abruptly and quickly | std::exit(1) |
Modern standard recommendation: use throw
, not exit
, unless you have a real reason.
Top comments (1)
std::abort()
.exit()
, you forgot to mentionstd::atexit()
.std::quick_exit()
andstd::at_quick_exit()
.assert()
.