38

Recently in my code I have been explicitly writing noexcept(false) on functions that I know do throw exceptions, mainly for people reading the code. However, I am wondering if this affects the behavior of my code or the way the compiler interprets it. Does it make any difference?

Note: I am aware that destructors are implicitly noexcept and that you have to specify noexcept(false) to change that, I am wondering about other functions.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
LB--
  • 2,506
  • 1
  • 38
  • 76

3 Answers3

35

Having no exception-specifier and explicitly stating noexcept(false) are equivalent, see §15.4/12:

A function with no exception-specification or with an exception-specification of the form noexcept(constant-expression) where the constant-expression yields false allows all exceptions.

So the compiler should not distinguish between them when considering exceptions.


More importantly, there's no need for you to be tacking on noexcept(false) to your functions. As a C++ developer, you should assume every function throws by default (which is why the standard takes this stance), so you're adding no new information by writing it out; it's a waste of time for everyone.

Rather, do mark the special case where a function definitely does not throw with noexcept, and do mark the cases where a function may throw depending on some condition with noexcept(condition).

If your function is purposefully the source of some exception E, write that in your documentation.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • 7
    Note that in C++11, destructors are by default `noexcept(true)`. If you want to override that, you'd have to add `noexcept(false)`. However, that's almost always a bad idea. (I'd venture to say it's always a bad idea; I'm only hedging with "almost" in case I'm not imaginative enough.) Huge swaths of code, including the standard library, assume that destructors always succeed and it's very difficult to compose code in a failure-recoverable way if clean-up can fail. In many situations, it's impossible (such as static initialization or multiple class members). – Adam H. Peterson Apr 27 '13 at 00:52
  • 1
    you could use `/* noexcept(false) */` to signal that you haven't accidentally forgotten to add `noexcept` to the interface – TemplateRex Aug 13 '14 at 20:40
  • 1
    I wish there was a way to mark a function such that it may throw even if compiler may determine through interprocedural analysis that it could not possibly throw. – kchoi Sep 09 '16 at 00:25
  • 1
    @kchoi: If the compiler is determining this, why does it matter? – GManNickG Sep 09 '16 at 17:54
  • Debugging embedded systems for bus errors, non-call exceptions (current ones have limitations?), etc. – kchoi Sep 18 '16 at 04:45
  • 1
    @kchoi: I guess I'm saying that if in reality the compiled binary won't throw from that function, and the compiler figures that out, what would you gain from telling it other wise? – GManNickG Sep 18 '16 at 04:47
  • @kchoi: I just realized I never answer your comment: the only way to do this is with compiler extensions, since it's the thing peeking past the language semantics. Unfortunately, I don't know any attributes/extensions on popular compilers for that. – GManNickG Sep 18 '16 at 04:48
  • @GManNickG It would be trivial to force compiler to keep 'maythrow' flag around. – kchoi Sep 29 '16 at 20:40
  • @kchoi: Sorry, I'm still not seeing the motivating use-case. :) If your compiler determined the code cannot throw, either compiler got it wrong and it actually can in which case that's a bug, or it really cannot. – GManNickG Sep 29 '16 at 21:08
  • @AdamH.Peterson with by default, do you mean if not explicitly defined by the programmer or for default destructors? – Matthias Jul 05 '19 at 17:53
0

The one case I can think of is on a destructor. I know you should never throw in a destructor. But in some cases you are stuck with code that does this and have no work around.

Since c++ automagically adds noexcept to destructors, this is the only way to undo it and prevent app terminate when the code throws.

https://github.com/chriskohlhoff/asio/issues/1216

from: https://akrzemi1.wordpress.com/2011/09/21/destructors-that-throw/

The compiler will still invisibly add specification noexcept to your destructor. And this means that the moment your destructor throws an exception, std::terminate will be called, even if there was no double-exception situation. If you are really determined to allow your destructors to throw, you will have to specify this explicitly; you have three options:

  1. Explicitly specify your destructor as noexcept(false),
  2. Inherit your class from another one that already specifies its destructor as noexcept(false).
  3. Put a non-static data member in your class that already specifies its destructor as noexcept(false).
  • Did you read the second paragraph/note of my question? I specifically don't want any answers related to the destructor. – LB-- Feb 08 '23 at 03:29
-2

In his book More Exceptional C++, Herb Sutter has the following snippet (pp. 130):

The right answer to the Example 19-1 is much simpler:

// Example 19-4: The right solution
//
T::~T() /* throw() */
{
 // ... code that won't throw ...
}

Example 19-4 demonstrates how to make a design decision instead of waffling.

Note that the throw() throws-nothing exception specification is only a comment. That's the style I've chosen to follow, in part because it turns out that exception specifications confer a lot less benefit than they're worth. Whether or not you decide to actually write the specification is a matter of taste.

(emphasis mine)

So, I feel I must point out that one of the leading experts in C++ exception-safe code seems to be against the whole concept of adding exception specifications for the compiler to use (but still leaving it in the code for the programmers to understand).

Just thought it may be interesting info...

Escualo
  • 40,844
  • 23
  • 87
  • 135
  • 4
    `throw()` and `noexcept(true)` are different exactly for this reason. I consider it _vital_ for move constructors and move assignments to be `noexcept(true)`, and would consider anything else to be a bug. – Mooing Duck Apr 26 '13 at 21:22
  • @MooingDuck: After reading this: http://herbsutter.com/2010/08/28/trip-report-august-2010-iso-c-standards-meeting/ I feel that his point still remains. Is it so? – Escualo Apr 26 '13 at 21:29
  • [Here](http://herbsutter.com/2010/03/13/trip-report-march-2010-iso-c-standards-meeting/) and [Here](http://www.gotw.ca/publications/mill22.htm) he mentions that `throw()` is bad because it does strange things. In the link you posted, he seems to have no reservations about applying `nothrow(true)` to all over the standard library. – Mooing Duck Apr 26 '13 at 21:44