Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is C++0x's `noexcept` checked dynamically?

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.

like image 446
rlbond Avatar asked May 04 '10 00:05

rlbond


People also ask

What is the point of Noexcept?

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.

What is the point of Noexcept C++?

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.

Does Noexcept make code faster?

That noexcept keyword is tricky, but just know that if you use it, your coding world will spin faster.

What happens if a Noexcept function throws?

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.


2 Answers

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

  1. every destructor is implicitly noexcept(true)
    • Arguably, this should be a strict requirement. Throwing destructors are always a bug.
  2. every extern "C" is implicitly noexcept(true)
    • Same argument again: exceptions in C-land are always a bug.
  3. every other function is implicitly noexcept(false) unless otherwise specified
  4. a noexcept(true) function must wrap all its noexcept(false) calls in try{}catch(...){}
    • By analogy, a const method cannot call a non-const method.
  5. This attribute must manifest as a distinct type in overload resolution, function pointer compatibility, etc.

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)

  • this would break backwards compatibility,
  • this arguably ought to be impossible, see point 1.

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.

like image 142
spraff Avatar answered Oct 07 '22 02:10

spraff


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 
like image 30
Vicente Botet Escriba Avatar answered Oct 07 '22 01:10

Vicente Botet Escriba