113

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 the 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 its deprecation.

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • 8
    Accodring to this [nice article](http://akrzemi1.wordpress.com/2011/06/10/using-noexcept/) 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. – Fiktik Oct 11 '12 at 06:17
  • 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. – curiousguy Nov 01 '19 at 08:12

3 Answers3

149

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

Community
  • 1
  • 1
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • 1
    +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 Feb 20 '13 at 14:16
  • Just found this http://stackoverflow.com/questions/10787766/when-should-i-really-use-noexcept ... – hmjd Feb 20 '13 at 14:17
  • @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. – Nicol Bolas Feb 20 '13 at 21:09
  • 2
    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. – hmjd Feb 20 '13 at 21:11
  • I wonder what happened to the case, that destructors shall not call functions that throw exceptions. – Alexander Oh Aug 26 '13 at 10:33
  • @Alex: It's fine for destructors to call throwing functions. They just can't allow those exceptions to *escape* the destructor call. – Nicol Bolas Aug 26 '13 at 10:35
  • 1
    @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. – Alexander Oh Aug 26 '13 at 10:47
  • @Alex: `noexcept` *is* a guarantee. If an exception tries to leave *any* function that is `noexcept`, then `std::terminate` will be called. – Nicol Bolas Aug 26 '13 at 10:48
  • 2
    @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. – Alexander Oh Aug 26 '13 at 11:58
  • @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. – Nicol Bolas Aug 26 '13 at 12:39
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/36258/discussion-between-alex-and-nicol-bolas) – Alexander Oh Aug 26 '13 at 13:14
  • 2
    @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). – Martin York Sep 17 '13 at 11:39
  • @MartinYork A difference in semantics that is irrelevant to the calling code. – curiousguy Oct 27 '19 at 03:10
  • @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 Oct 27 '19 at 03:13
  • "_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) – curiousguy Oct 27 '19 at 03:15
  • @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. – Nicol Bolas Oct 27 '19 at 03:19
  • @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 Oct 27 '19 at 03:24
35

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.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • 1
    But if a virtual function has `throw()`/`noexcept`, compile time checking ensure that an overrider also has. – curiousguy Oct 28 '19 at 04:56
2

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.

MAChitgarha
  • 3,728
  • 2
  • 33
  • 40
ma13
  • 53
  • 1
  • 9