13

A debate came up at work regarding how much to care about using noexcept. We all know that noexcept doesn't really do a huge amount for the compiler's optimiser except for externally defined code which the compiler otherwise has to assume can throw because it can't know its implementation, so the only real other performance benefit of marking things noexcept is for code which makes use of std::move_if_noexcept<> which it would be assumed would be mostly STL containers and their algorithms.

The assessment would therefore be this: do not use noexcept unless:

  1. extern functions and classes where the implementation of a callable isn't known to the compiler.

  2. Move constructors, move assignment operators and swap for any type which might be contained in a STL container.

  3. Otherwise don't worry about it.

Is this a fair assessment? Are there other places in the STL which generate much more optimal code if something is noexcept? If so, which STL implementation is this and what needs to be marked noexcept for it to work, and what performance benefit results (fewer memory allocations, lower complexity)?

Edit: Made CashCow's suggested change to wording.

Niall Douglas
  • 9,212
  • 2
  • 44
  • 54

1 Answers1

2

Is this a fair assessment?

No... it's unnecessarily fragile during code evolution/maintenance. Consider what happens if you follow your rules for this code...

// awesome_lib.h
void f() noexcept; // out-of-line implementation: { }

// awesome_app.cpp
void c1() noexcept; // out-of-line implementation: { f(); }

// cool_app.cpp
void c2() noexcept; // out-of-line implementation: { f(); }

...then say f() wants to report a new class of issue via exceptions, so it removes noexcept and conditionally throws... unless all the client code calling f() - c1, c2, ... is found and updated, the applications may std::terminate instead of letting the exception propagate to whatever catch clause might otherwise be available. Why would you want that? Yes you could use the noexcept operator to express the noexcept nature of c1 and c2 in terms of f and other called functions, but that's verbose and fragile. It's not like const where compiler errors help you keep things consistent.

It's better to make targeted use of noexcept where it's required by a specific profiling-lead optimisation opportunity.

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • So you are saying that noexcept reduces your ability to break ABI safely? I am afraid I don't buy this at all - a function changing its noexcept is identical to a function changing the type of a parameter, it is an ABI break and you lose binary compatibility. There is absolutely nothing special about noexcept in this regard. – Niall Douglas Oct 21 '14 at 11:37
  • I will say though you make a good point that compilers should be warning much more severely when a noexcept function calls a non-noexception function without a surrounding try...catch. I would assume the reason why is because any use of the STL would spew tons of warnings given how inconsistent noexcept use is in the STL itself. I would still personally like the compiler to warn for my code though, maybe it'll arrive in time. – Niall Douglas Oct 21 '14 at 11:39
  • @NiallDouglas: "So you are saying..." - not sure how you concluded that, if I'd meant ABI I'd have mentioned it. I'm talking purely about the code edits needed (to avoid unnecessary `std::terminate` calls) before recompiling apps after a lower level functions removes `noexcept` - nothing to do with ongoing ability to link non-recompiled objects. – Tony Delroy Oct 21 '14 at 11:41
  • 1
    Ah okay fair point. BTW, I completely agree that how noexcept was implemented is stupid and induces far too much typing and fatal exit potential brittleness, plus when combined with allocators it's making a mess of the STL. There should be a noexcept(auto) too to let noexcept-ness propagate. And there should be a new noalloc(boolean) which says a function never allocates memory, that lets you avoid jumping through hoops when combining noexcept with allocators. – Niall Douglas Oct 21 '14 at 11:48
  • 2
    @NiallDouglas there are some [proposals](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3207.htm) - worth a read.... – Tony Delroy Oct 21 '14 at 11:59
  • Not the first time Jason has beaten me to it! Thanks for the link though, it shows me that I am not alone in the solution to that problem. I still await someone to beat me to a noalloc() modifier ... – Niall Douglas Oct 21 '14 at 21:38