user2138149
user2138149

Reputation: 17362

What is the compiler and runtime behaviour of throwing an exception inside a noexcept function in C++?

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

Answers (4)

mediocrevegetable1
mediocrevegetable1

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 [or std::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

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

ChrisMM
ChrisMM

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

Ghasem Ramezani
Ghasem Ramezani

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

Related Questions