- 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?
noexcept
is tricky, as it is part of the functions interface. Especially, if you are writing a library, your client code can depend on the noexcept
property. It can be difficult to change it later, as you might break existing code. That might be less of a concern when you are implementing code that is only used by your application.
If you have a function that cannot throw, ask yourself whether it will like stay noexcept
or would that restrict future implementations? For example, you might want to introduce error checking of illegal arguments by throwing exceptions (e.g., for unit tests), or you might depend on other library code that could change its exception specification. In that case, it is safer to be conservative and omit noexcept
.
On the other hand, if you are confident that the function should never throw and it is correct that it is part of the specification, you should declare it noexcept
. However, keep in mind that the compiler will not be able to detect violations of noexcept
if your implementation changes.
- 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)?
There are four classes of functions that should you should concentrate on because they will likely have the biggest impact:
- move operations (move assignment operator and move constructors)
- swap operations
- memory deallocators (operator delete, operator delete[])
- destructors (though these are implicitly
noexcept(true)
unless you make them noexcept(false)
)
These functions should generally be noexcept
, and it is most likely that library implementations can make use of the noexcept
property. For example, std::vector
can use non-throwing move operations without sacrificing strong exception guarantees. Otherwise, it will have to fall back to copying elements (as it did in C++98).
This kind of optimization is on the algorithmic level and does not rely on compiler optimizations. It can have a significant impact, especially if the elements are expensive to copy.
- 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.
The advantage of noexcept
against no exception specification or throw()
is that the standard allows the compilers more freedom when it comes to stack unwinding. Even in the throw()
case, the compiler has to completely unwind the stack (and it has to do it in the exact reverse order of the object constructions).
In the noexcept
case, on the other hand, it is not required to do that. There is no requirement that the stack has to be unwound (but the compiler is still allowed to do it). That freedom allows further code optimization as it lowers the overhead of always being able to unwind the stack.
The related question about noexcept, stack unwinding and performance goes into more details about the overhead when stack unwinding is required.
I also recommend Scott Meyers book "Effective Modern C++", "Item 14: Declare functions noexcept if they won't emit exceptions" for further reading.
move_if_nothrow
(or whatchamacallit) will see a performance improvement if there's a noexcept move ctor. – R. Martinho Fernandes