I have written about handling exceptions some time ago, and about the levels of exception safety last week. What I have not touched yet are exception specifications. I will catch up on those with this post.

C++98 had the possibility to denote the types of exceptions that could be thrown from a given function by using throw(<exception list>) . In theory, the runtime had to check if any exception emitted by the function was indeed in that list or derived from one of the types in the list. If it wasn’t, the handler std::unexpected would be called.

I say “in theory” because some compilers would just ignore nonempty exception specification, as they were difficult to implement. In addition, those dynamic exception specifications work in a way that is not what most users would expect. Therefore many authors discouraged the use of exception specifications, except maybe throw() which meant the function in question should have the nothrow guarantee.

Since C++11, dynamic exception specifications are deprecated. Instead we got noexcept as a replacement for the only usable specification there was, i.e. the empty one.

Don’t use C++98’s exception specifications. Use `noexcept` instead, where applicable.

The noexcept specifier

The noexcept specifier comes in two forms: a plain noexcept and a parametrized form. Either of them can be used in function declarations and in lambda declarators. They have to be inserted after reference and const/volatile qualifiers or, in the case of lambdas, before the mutable qualifier, if present, and before the optional attributes:

struct X { auto f() const noexcept -> int; void g() noexcept { auto lam = []() noexcept { return 42; }; std::cout << lam() << '

'; } ~X(); //implicitly noexcept };

The plain form in the examples simply states that the function will not throw any exception. If the function throws an exception anyway, std::terminate will be called. That means, throw() , which was the only really usable part of the empty dynamic exception specifications, essentially has survived.

It is important to note that destructors are always implicitly noexcept , even if they contain functions that may throw or even throw expressions. This is just the right thing to have, because destructors are called implicitly during stack unwinding and therefore should never throw an exception themselves. Another point is that every other compiler generated special member function is noexcept if the operations it calls are noexcept as well.

If you are writing the special member functions, declare them `noexcept` where applicable.

But there is more to noexcept . Consider a template, where, depending on the template parameter, a function should or should not give the nothrow guarantee:

template <class T> T copy(T const& original) /* maybe noexcept? */ { return original; }

This is a silly example, but it shows the point: this function could be noexcept if the copy constructor of T can not throw an exception. For starters, we can be sure that this is sure for any builtin types. We can use a C++11 type trait is_fundamental to check for those types, and the parametrized form of noexcept to make the template conditionally noexcept :

template <class T> T copy(T const& original) noexcept(std::is_fundamental<T>::value) { return original; }

This works pretty straight forward: noexcept( <expression> ) declares the function as not throwing if and only if the expression is true. So our little example is declared noexcept only for fundamental types. For any other type it is allowed to throw any exception. Since it is evaluated at compile time, <expression> must be a compile time constant.

Of course we’re not done yet. There are lots of other types that won’t throw an exception in the copy constructor. In fact, there will surely be types that are not defined yet but will be some time in the future, which have noexcept copy constructors. How can we prepare our function for those types without requiring the authors to specialize some traits – which they usually won’t do for us?

The noexcept operator

As it turns out, noexcept can not only be used as a specifier for functions, it is also an operator. Which one it is depends on the context. The noexcept operator is executed at compile time and takes the argument expression without executing it. It returns either true or false, depending on whether the compiler finds something in the expression that could throw an exception.

The noexcept operator returns false if the expression contains a call to a function that is not noexcept , to operators that could possibly throw (e.g. dynamic_cast with references), or of course a throw expression. In all other cases it returns true. So, for our example, we just need to use the noexcept operator to check if constructing a T from our argument might throw, and pass the result to the noexcept specifier of our function template:

template <class T> T copy(T const& original) noexcept(noexcept( T(original) )) { return original; // noexcep specifier --^ ^-- noexcept operator }

If that looks a bit hard to read, I have good news for you: There are a whole bunch of type traits in the standard library that deal with special operations and whether they might throw. In our case the correct trait would be is_nothrow_copy_constructible :

template <class T> T copy(T const& original) noexcept(std::is_nothrow_copy_constructible<T>::value) { return original; }

While this is even a bit more verbose than the version using the noexcept operator, it is also clearer to read and therefore preferable to the nesting of the noexcept operator inside the noexcept specifier.

Consider writing your own `is_nothrow_…` traits if you have complex conditions for your `noexcept` specifiers

The noexcept operator and traits that are implemented using it is not only useful for noexcept specifiers. There are also techniques that switch between different operations depending on whether the default operation may throw or not. For example, the utility function move_if_noexcept in the standard library allows to move or copy an object, depending on whether the move may throw.

Conclusion

While it is not necessarily a feature you should use on every class and every function you write, noexcept is worth keeping in mind, since it can help to reason about your code. In addition, libraries can often call more efficient algorithms if they know that the functions they call don’t throw exceptions.