noexcept and destructors
The third guarantee, no exceptions, is written right in the function's declaration. It is like a sign on a floor: "no alarm balls fly out of here". The floors below trust the sign and put up no net for this floor.
What if a ball flies out anyway? The promise is broken, and nobody gets to catch the ball further down: the whole building is shut.
The noexcept promise
The word noexcept after the parameter list promises that no exception leaves the function:
int twice(int x) noexcept {
return x * 2;
}Why is this needed? Both people and the standard library read the promise. For example, a growing std::vector can move its elements faster when it knows the move throws no exception.
What happens when the promise is broken:
- the compiler does not forbid
throwin anoexceptfunction: GCC and Clang only warn when they see an exception leaving it; - if an exception does leave a
noexceptfunction,std::terminateis called and the program ends; - no handler outside catches such an exception, even if its type fits;
- an exception thrown and caught inside the function itself does not break the promise.
Destructors and noexcept
Every destructor is noexcept, even when the word is not written. So an exception that leaves a destructor calls std::terminate too.
Recall stack unwinding: destructors run exactly when one exception is already in flight. If a destructor threw a second one, the program would have to choose between two balls. C++ does not choose and ends the program.
Interviewers like this question: "why must a destructor not throw?" The answer: a destructor is implicitly noexcept, and an exception leaving it calls std::terminate.
Common mistake
A destructor reports an error with an exception:
struct File {
bool saved = false;
~File() {
if (!saved) {
throw std::runtime_error("not saved"); // ✗
}
}
};warning: '~File' has a non-throwing exception specification but can still throw [-Wexceptions]The program builds: this is Clang's warning, and GCC gives a similar one. But when a File whose saved is false is destroyed, std::terminate is called, and a try around the object does not help.
A destructor must not throw. A separate method such as save(), called before the object is destroyed, reports the error. There the exception can still be caught.
Key points
noexceptpromises that no exception leaves the function; the compiler does not forbidthrowin it.- An exception that leaves a
noexceptfunction callsstd::terminate, and no outer handler catches it. - Every destructor is
noexcept, even without the word. - A destructor throws no exceptions: a separate method, called earlier, reports the error.
Subscribe to take the course
The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.