The noexcept
keyword can be appropriately applied to many function signatures, but I am unsure as to when I should consider using it in practice. Based on what I have read so far, the last-minute addition of noexcept
seems to address some important issues that arise when move constructors throw. However, I am still unable to provide satisfactory answers to some practical questions that led me to read more about noexcept
in the first place.
There are many examples of functions that I know will never throw, but for which the compiler cannot determine so on its own. Should I append noexcept
to the function declaration in all such cases?
Having to think about whether or not I need to append noexcept
after every function declaration would greatly reduce programmer productivity (and frankly, would be a pain in the neck). For which situations should I be more careful about the use of noexcept
, and for which situations can I get away with the implied noexcept(false)
?
When can I realistically expect to observe a performance improvement after using noexcept
? In particular, give an example of code for which a C++ compiler is able to generate better machine code after the addition of noexcept
.
Personally, I care about noexcept
because of the increased freedom provided to the compiler to safely apply certain kinds of optimizations. Do modern compilers take advantage of noexcept
in this way? If not, can I expect some of them to do so in the near future?
I think it is too early to give a "best practices" answer for this as there hasn't been enough time to use it in practice. If this was asked about throw specifiers right after they came out then the answers would be very different to now.
Having to think about whether or not I need to append
noexcept
after every function declaration would greatly reduce programmer productivity (and frankly, would be a pain).
Well, then use it when it's obvious that the function will never throw.
When can I realistically expect to observe a performance improvement after using
noexcept
? [...] Personally, I care aboutnoexcept
because of the increased freedom provided to the compiler to safely apply certain kinds of optimizations.
It seems like the biggest optimization gains are from user optimizations, not compiler ones due to the possibility of checking noexcept
and overloading on it. Most compilers follow a no-penalty-if-you-don't-throw exception handling method, so I doubt it would change much (or anything) on the machine code level of your code, although perhaps reduce the binary size by removing the handling code.
Using noexcept
in the big four (constructors, assignment, not destructors as they're already noexcept
) will likely cause the best improvements as noexcept
checks are 'common' in template code such as in std
containers. For instance, std::vector
won't use your class's move unless it's marked noexcept
(or the compiler can deduce it otherwise).
As I keep repeating these days: semantics first.
Adding noexcept
, noexcept(true)
and noexcept(false)
is first and foremost about semantics. It only incidentally condition a number of possible optimizations.
As a programmer reading code, the presence of noexcept
is akin to that of const
: it helps me better grok what may or may not happen. Therefore, it is worthwhile spending some time thinking about whether or not you know if the function will throw. For a reminder, any kind of dynamic memory allocation may throw.
Okay, now on to the possible optimizations.
The most obvious optimizations are actually performed in the libraries. C++11 provides a number of traits that allows knowing whether a function is noexcept
or not, and the Standard Library implementation themselves will use those traits to favor noexcept
operations on the user-defined objects they manipulate, if possible. Such as move semantics.
The compiler may only shave a bit of fat (perhaps) from the exception handling data, because it has to take into account the fact that you may have lied. If a function marked noexcept
does throw, then std::terminate
is called.
These semantics were chosen for two reasons:
noexcept
even when dependencies do not use it already (backward compatibility)noexcept
when calling functions that may theoretically throw, but are not expected to for the given argumentsIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With