Loading lessons...
Exception Safety and noexcept
Exception Safety and noexcept
Throwing and catching is more refined than it first looks. C++ gives you a catch-all for anything, a promise (noexcept) that a function won't throw, and a well-defined way the stack is cleaned up while an exception travels.
Catching anything
When the exact type doesn't matter, you can catch any exception with the ellipsis ...:
try {
std::vector<int> v(10);
v.at(20) = 5; // out of range -> throws
} catch (...) {
std::cout << "Something went wrong";
}
catch (...) catches every type with no variable to inspect. Use it for belt-and-braces: catch, log, and end.
What happens when no catch type matches
If an exception is thrown and not caught anywhere, the program terminates - it crashes out of the run. So every throw deserves a matching catch, or a program that stops unexpectedly.
noexcept: the promise
A function can declare it will not throw:
void helper() noexcept {
// this function promises never to throw
}
If it throws anyway, the runtime calls std::terminate and the program ends. Containers like std::vector use the noexcept guarantee to decide between moving or copying element values.
Stack unwinding
When an exception is thrown, the stack "unwinds": as control leaves each function frame, the destructors of local objects still run, cleaning up the resources:
struct Thing {
~Thing() { std::cout << "destroyed "; }
};
void f() {
Thing t; // constructed
throw 1; // unwinding runs t's destructor anyway
}
int main() {
try { f(); } catch (int) { std::cout << "caught"; }
}
That prints "destroyed caught": destructors run for every local frame the exception passes through, so resources are cleaned up even when control leaps out.
TL;DR
catch(...)matches every exception type.- An uncaught exception terminates the program.
noexceptis a promise the function will not throw.- Stack unwinding runs destructors as the exception travels upward.
- Unwinding plus RAII is what makes exceptions safe.