Is there any difference between throw()
and noexcept
other than being checked at runtime and compile time, respectively?
This Wikipedia C++11 article suggests that the C++03 throw specifiers are deprecated.
Why so, is noexcept
capable enough to cover all that at compile time ?
[Note: I checked this question and this article, but couldn't determine the solid reason for deprecation.]
The noexcept operator performs a compile-time check that returns true if an expression is declared to not throw any exceptions. It can be used within a function template's noexcept specifier to declare that the function will throw exceptions for some types but not others.
noexcept is an improved version of throw(), which is deprecated in C++11. Unlike pre-C++17 throw(), noexcept will not call std::unexpected, may or may not unwind the stack, and will call std::terminate, which potentially allows the compiler to implement noexcept without the runtime overhead of throw().
There are two good reasons for the use of noexcept: First, an exception specifier documents the behaviour of the function. If a function is specified as noexcept, it can be safely used in a non-throwing function. Second, it is an optimisation opportunity for the compiler.
Theoretically speaking, noexcept would improve performance. But it might also cause some problems on the other hand. In most of cases, it shouldn't be specified because the pros are too few to be considered and it might make your code upgrading painful.
Exception specifiers were deprecated because exception specifiers are generally a terrible idea. noexcept
was added because it's the one reasonably useful use of an exception specifier: knowing when a function won't throw an exception. Thus it becomes a binary choice: functions that will throw and functions that won't throw.
noexcept
was added rather than just removing all throw specifiers other than throw()
because noexcept
is more powerful. noexcept
can have a parameter which compile-time resolves into a boolean. If the boolean is true, then the noexcept
sticks. If the boolean is false, then the noexcept
doesn't stick and the function may throw.
Thus, you can do something like this:
struct<typename T> { void CreateOtherClass() { T t{}; } };
Does CreateOtherClass
throw exceptions? It might, if T
's default constructor can. How do we tell? Like this:
struct<typename T> { void CreateOtherClass() noexcept(is_nothrow_default_constructible<T>::value) { T t{}; } };
Thus, CreateOtherClass()
will throw iff the given type's default constructor throws. This fixes one of the major problems with exception specifiers: their inability to propagate up the call stack.
You can't do this with throw()
.
noexcept
isn't checked at compile time.
An implementation shall not reject an expression merely because when executed it throws or might throw an exception that the containing function does not allow.
When a function that is declared noexcept
or throw()
attempts to throw an exception the only difference is that one calls terminate
and the othe calls unexpected
and the latter style of exception handling has effectively been deprecated.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With