Reputation: 17362
What is the compiler and runtime behaviour of throwing an exception inside a function which is declared noexcept
?
According to a quick experiment with some code, the gcc compiler produces the following warning message when a throw
statement is included inside of a function which is declared noexcept
:
warning `throw` will always call `terminate` [-Wterminate]
This is not what I had anticipated. I would have expected this to fail to compile.
If I understand correctly the warning indicates that my code compiled successfully however if the throw statement is ever reached, then terminate is called instead.
I would guess that the compiler substituted my throw
statement for a terminate statement of some kind?
Can anyone provide further clarity on the issue? What is it about noexcept
which guarantees that exceptions cannot be thrown from within a function, even if I deliberatly ignore the noexcept
statement and throw an error myself anyway?
Upvotes: 0
Views: 645
Reputation: 4217
This is an excerpt from https://en.cppreference.com/w/cpp/language/noexcept_spec that should clear things up:
Non-throwing functions are permitted to call potentially-throwing functions. Whenever an exception is thrown and the search for a handler encounters the outermost block of a non-throwing function, the function
std::terminate
[orstd::unexpected
(until C++17)] is called:extern void f(); // potentially-throwing void g() noexcept { f(); // valid, even if f throws throw 42; // valid, effectively a call to std::terminate }
So basically when there is a throw
in a noexcept
function and there it is not handled, std::terminate
is called instead.
Upvotes: 2
Reputation: 170231
noexcept
is not a guarantee for the function author, but a promise on their part. If the author fails to uphold that promise (directly or indirectly) std::terminate
is called. Only callers of the noexcept
function can consider it a guarantee.
It's not a hard error to throw
because checking whether a general piece of code throws an exception is undecidable in general (and indeed equivalent to the halting problem), so compilers aren't forced to diagnose it.
In this case, GCC is operating under a simple heuristic (seeing the throw
expression directly) and warning you about breaking the promise you made when marking the function noexcept
.
Upvotes: 1
Reputation: 10102
The standard actually specifies that a compiler should not reject the code.
From [except.spec]/5
Whenever an exception is thrown and the search for a handler ([except.handle]) encounters the outermost block of a function with a non-throwing exception specification, the function std::terminate is invoked ([except.terminate]). [Note 1: An implementation is not permitted to reject an expression merely because, when executed, it throws or might throw an exception from a function with a non-throwing exception specification. — end note]
Upvotes: 3
Reputation: 2888
In C++ functions could throw exception or couldn't throw exceptions. If a function is declared with an empty noexcept-specifier, it's a non-throwing function, and if we throw an exception from a non-throwing function. We will catch up by std::terminate
.
https://en.cppreference.com/w/cpp/language/noexcept_spec
Upvotes: 2