Difference between C++03 throw() specifier C++11 noexcept

26,907

Solution 1

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().

Solution 2

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.

Solution 3

std::unexpected() is called by the C++ runtime when a dynamic exception specification is violated: an exception is thrown from a function whose exception specification forbids exceptions of this type.

std::unexpected() may also be called directly from the program.

In either case, std::unexpected calls the currently installed std::unexpected_handler. The default std::unexpected_handler calls std::terminate.

Share:
26,907

Related videos on Youtube

iammilind
Author by

iammilind

"Among programming languages, I am C++ ..." — BG 10.19...

Updated on April 18, 2020

Comments

  • iammilind
    iammilind about 4 years

    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.]

    • Fiktik
      Fiktik over 11 years
      Accodring to this nice article also noexcept may incur runtime checks. The main difference between them being that breaking noexcept causes std::terminate while breaking throw causes std::unexpected. Also a slightly different stack unwinding behaviour in these cases.
    • curiousguy
      curiousguy over 4 years
      There is nothing "compile time" checked with some exception specifications that is "runtime" checked on others. It's just a myth created by opponents of C++ exception specifications.
  • hmjd
    hmjd about 11 years
    +1 Useful answer, for me anyway. Still searching for an answer that says why I would want to use noexcept. I never used throw() specifier, ever and am attempting to determine if noexcept actually provides any benefit (other than compiler checked documentation).
  • hmjd
    hmjd about 11 years
  • Nicol Bolas
    Nicol Bolas about 11 years
    @hmjd: "Still searching for an answer that says why I would want to use noexcept." You won't find an answer to that here because that's not the question that was asked.
  • hmjd
    hmjd about 11 years
    Yep, I know that. Was just researching noexcept and reading a few questions/answers on it. The most important reason I found was that some (possibly all) of the STL containers will not use the move constructor if it is not declared as noexcept, which I didn't realise.
  • Alexander Oh
    Alexander Oh over 10 years
    I wonder what happened to the case, that destructors shall not call functions that throw exceptions.
  • Nicol Bolas
    Nicol Bolas over 10 years
    @Alex: It's fine for destructors to call throwing functions. They just can't allow those exceptions to escape the destructor call.
  • Alexander Oh
    Alexander Oh over 10 years
    @NicolBolas agree. but if noexcept would be a guarantee, the compiler could check whether a function may throw or not in a destructor. Thus being able to warn a programmer that a function is noexcept or not.
  • Nicol Bolas
    Nicol Bolas over 10 years
    @Alex: noexcept is a guarantee. If an exception tries to leave any function that is noexcept, then std::terminate will be called.
  • Alexander Oh
    Alexander Oh over 10 years
    @NicolBolas the runtime calls std::terminate. which is WAY WORSE! code can sneak into releases that have functions marked noexcept and at runtime (meaning at customer sites) violations are detected. I meant the compiler guarantees to generate code that doesn't throw exceptions in the first place.
  • Nicol Bolas
    Nicol Bolas over 10 years
    @Alex: C++ is not a safe language. It is always the responsibility of the programmer to ensure the integrity of a C++ program. The same goes here: you are allowed to call functions that aren't marked noexcept. The language trusts that you will either call these functions in such a way that they will not throw, or that you will call these function in such a way that you will catch any exceptions they throw. There is no reason to force C++ programmers to only restrict themselves to functions explicitly labeled noexcept. That would break tons of code.
  • Alexander Oh
    Alexander Oh over 10 years
  • Martin York
    Martin York over 10 years
    @NicolBolas: One other difference worth noting. If a function is marked throws() then if an exception is thrown the stack must be unwound upto the scope of that function (so all automatic variables in the function are destroyed) at which point terminate() is called (via unexpected()). If a function is marked noexcept then if an exception is thrown then terminate is called (the unwinding of the stack is implementation defined detail).
  • curiousguy
    curiousguy over 4 years
    @MartinYork A difference in semantics that is irrelevant to the calling code.
  • curiousguy
    curiousguy over 4 years
    @hmjd "The most important reason I found was that some (possibly all) of the STL containers will not use the move constructor if it is not declared as noexcept" Yes and changing the function decoration from throw() to noexcept was not needed to do that.
  • curiousguy
    curiousguy over 4 years
    "Exception specifiers were deprecated because exception specifiers are generally a terrible idea." Then the new style is equally "terrible" as the exact same critics apply, except the less useful "throw some exceptions" have been removed (which was never part of the central argument against old style spec)
  • Nicol Bolas
    Nicol Bolas over 4 years
    @curiousguy: You know, there were several sentences after the first one. Indeed, the very next sentence addresses this exact point. It's almost like I was going somewhere with that. Hence the use of qualifiers like "generally" and so forth.
  • curiousguy
    curiousguy over 4 years
    @NicolBolas They were found to be of little use, but their bad reputation is similar to the bad rep of MI in many languages, it's based on completely irrelevant or bogus claims, bad example, bad understanding... Bad understanding is fixed by better explanations, not changing language syntax and semantics. I'm not saying that the full power of old throw spec was worth keeping given the (relatively extremely small) additional language and impl complexity they caused, but denigration of a tool is bad and awful when it propages deep misunderstanding of programming.
  • curiousguy
    curiousguy over 4 years
    But if a virtual function has throw()/noexcept, compile time checking ensure that an overrider also has.