Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discussion about when to use noexcept #45

Closed
rrahn opened this issue Apr 1, 2020 · 2 comments
Closed

Discussion about when to use noexcept #45

rrahn opened this issue Apr 1, 2020 · 2 comments

Comments

@rrahn
Copy link
Contributor

rrahn commented Apr 1, 2020

Resources:

tl;dr

Use noexcept when it makes sense for the performance (move, swap, ...) or it can be guaranteed the function will not fail.

Summary

So my take from reading more about the experiences people made with noexcept is the following.

First of all see noexcept not as a no-throw guarantee but as a no-fail guarantee. That means you can make sure that the function won't fail - so there is no need for any error handling, wether it is due to error return codes or throws. For example most of the cases comparsion operators or functions that does some arithmetic operations which won't overflow or underflow are no-fail. Then declaring them noexcept would be fine and express the intent. Especially for those who use this function in their code and need to reason about their guarantees.
Another point would be if the thing that fails is so severe that it you cannot recover from it. In this case throwing an exception does not make sense at all and calling terminate is the only sane thing to to.
Some benefits a noexcept function should bring is optimised code. There are two different kind of optimisations. First, the compiler doesn't have to do a certain amount of setup to prepare for stack unwinding in case something breaks. But as far as I can read it merely means that the code size will be reduced. But exception handling code is added to spearate parts of the code and only called when it fails so you usually do not expect runtime penalties. If you think it does than measure it to be sure.
The only important thing from a pure technical point of view is to use noexcept, when you can use it for static dispatching and call optimised functions baed on this. So far it seems that declaring move-constructors, move-assignment, destructors (which are implicitly declared noexcept as long as all member destructors or base class destructors are non-throwing) as well as swap overloads noexcept is important to activate more performant branches within the STL, e.g. when reszing a vector. In fact, this boils down to whether or not there are specific type traits to check if the functions are noexcept which can be done currently with all constructors, destructor and assignment operators and swap function.

Based on this I would argue on the following rules:

  1. Always use noexcept for move-constructor, move-assignment, destructor and user defined swap (unless of course it can't be guaranteed)
  2. Always use noexcept if it participates in overload dispatching to perform more optimised routines in other expressions than the ones named in 1.
  3. Always use noexcept for function you guarantee they won't fail. (That also includes calling functions from other libraries that are not declared noexcept, for example upper_bound, but cannot throw, or if they do than something is way off and not in a recoverable state.)
  4. Use noexcept when it in general improves compiletime/runtime but measure it to be sure.

In generic contexts where you can't be sure but merely want to preserve the state of the generic expression use the noexcept-operator, i.e. noexcept(noexcept(expr))

@smehringer
Copy link
Member

Resolution:

We will keep close to the standard.
The standard usually has no noexcept in many cases, unless it is required for move semantics.
We therefore

  • use noexpect whenever we can guarantee it
  • do not use noexcept on explicitly defaulted constructors/assignment operators unless we really need to enforce this (this also goes for constexpr)
  • use conditional noexcept in cases where we deem noexcept as critical, those cases so far are:
    • move constructor, move assignment, destructor, user-defined swap
    • when it is performance critical whitin an algorithm (needs tests)
    • iter_move, iter_swap?

We should make wiki entry when we are sure.

@smehringer
Copy link
Member

We should make wiki entry when we are sure.

Done. https://github.com/seqan/seqan3/wiki/Exceptions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants