I am curious about the rationale behind noexcept
in the C++0x FCD. throw(X)
was deprecated, but noexcept
seems to do the same thing. Is there a reason that noexcept
isn't checked at compile time? It seems that it would be better if these functions were checked statically that they only called throwing functions within a try
block.
noexcept is primarily used to allow "you" to detect at compile-time if a function can throw an exception. Remember: most compilers don't emit special code for exceptions unless it actually throws something.
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.
That noexcept keyword is tricky, but just know that if you use it, your coding world will spin faster.
When an exception is thrown from a function that is declared noexcept or noexcept(true) , std::terminate is invoked. When an exception is thrown from a function declared as throw() in /std:c++14 mode, the result is undefined behavior. No specific function is invoked.
Basically, it's a linker problem, the standards committee was reluctant to break the ABI. (If it were up to me, I would do so, all it really requires is library recompilation, we have this situation already with thread enablement, and it's manageable.)
Consider how it would work out. Suppose the requirements were
noexcept(true)
noexcept(true)
noexcept(false)
unless otherwise specifiednoexcept(true)
function must wrap all its noexcept(false)
calls in try{}catch(...){}
Sounds reasonable, right?
To implement this, the linker needs to distinguish between noexcept(true)
and noexcept(false)
versions of functions, much as you can overload const and const versions of member functions.
So what does this mean for name-namgling? To be backwards-compatible with existing object code we would require that all existing names are interpreted as noexcept(false)
with extra mangling for the noexcept(true)
versions.
This would imply we cannot link against existing destructors unless the header is modified to tag them as noexcept(false)
I spoke to a standards committe member in person about this and he says that this was a rushed decision, motivated mainly by a constraint on move operations in containers (you might otherwise end up with missing items after a throw, which violates the basic guarantee). Mind you, this is a man whose stated design philosophy is that fault intolerant code is good. Draw your own conclusions.
Like I said, I would have broken the ABI in preference to breaking the language. noexcept
is only a marginal improvement on the old way. Static checking is always better.
If I remember throw has been deprecated because there is no way to specify all the exceptions a template function can throw. Even for non-template functions you will need the throw clause because you have added some traces.
On the other hand the compiler can optimize code that doesn't throw exceptions. See "The Debate on noexcept, Part I" (along with parts II and III) for a detailed discussion. The main point seems to be:
The vast experience of the last two decades shows that in practice, only two forms of exceptions specifications are useful:
The lack of an overt exception specification, which designates a function that can throw any type of exception:
int func(); //might throw any exception
A function that never throws. Such a function can be indicated by a throw() specification:
int add(int, int) throw(); //should never throw any exception
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