Modern C++ Features – keyword `noexcept`

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() << '\n';
  }
  ~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( &lt;expression&gt; ) 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, &lt;expression&gt; 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.

Special member functions should be among the first functions to make `noexcept` correct. Beyond that, consider to declare swap and cleanup functions `noexcept` as well.

Previous Post
Next Post

15 Comments


  1. “I say “in theory” because some compilers would just ignore nonempty exception specification, as they were difficult to implement”

    What part of the nonempty exception specification is difficult to implement? It looks like a simple implicit try-catch block around the function would do the job.

    Reply

    1. The exception specifications also had a huge impact on virtual functions and functions overriding them. They basically formed an additional type system to be considered besides covariance etc. Googling for “exceptions shadow type system” will give you a more sophisticated answer.

      Reply

  2. Hello. Good post!
    I’m implementing my derived classes using noexcept(std::is_nothrow_copy_constructible::value) but when the base class is an abstract class, std::is_constructible::value is false (an abstract class cannot be instanciated) so the std::is_nothrow_copy_constructible::value is false too, even if the base class has a noexcept(true) specifier. In consequence, derived class is not eligible to move_if_noexcept even if actually not throwing.

    Reply

  3. This blog awesome and i learn a lot about programming from here.The best thing about this blog is that you doing from beginning to experts level.

    Reply

    1. Thank you! I try to mix it up a bit – beginners can stretch their boundaries with expert level stuff, and experts sometimes learn something new even from beginner topics 🙂

      Reply

  4. The thing about throwing destructors is, “What do you do with the information that a destructor has thrown?” A destructor is called to clean up after an object, and it is called to clean up after an exception. Destruction needs to have “best-effort” semantics.

    If I ruled the world, destructors would swallow exceptions unless they were specified with an exception specification saying they can throw specific exceptions. This position will no doubt be controversial. :-).

    Reply

  5. There is a big problem with noexcept.

    On Windows at least, you can convert structured exceptions (which represent hardware exceptions like access violations) into C++ exceptions. The problem with noexcept is that there is no way to ensure code is free of hardware exceptions. Noexcept causes the sudden, irrevocable termination of programs. This makes C++ programs using noexcept extremely brittle.

    My experience has been that programs that dereference nil are usually capable of continuing. Some part of the computation has to be abandoned, but the program can usually continue. The decision to terminate should remain under program control, but noexcept takes this control away.

    Reply

    1. Yep, this is true and often overlooked by most developers because they prioritize correctness over fault-tolerance. In most cases this is the right call, but some systems do require fault-tolerance over correctness. In the Windows world this means converting SEH exceptions to C++ exceptions (if you develop in C++) which makes noexcept a big no-no in most cases. Each use of noexcept then has to be carefully examined.

      Reply

    2. If you’re calling code that might throw a structured exception from inside a nothrow function. Then the right thing to do is to have a __try, __except block in that function and handle it there.

      Reply

  6. I strongly dislike throwing destructors too – what does it mean to fail to destroy an object? However, there are idioms that rely on them, for example a guard object that will either commit or roll-back a database transaction at the end of a function. What happens when the network connection to the database goes down? There may be solutions that do not involve throwing, but that is not an unreasonable approach.

    Similarly, and scope-guard like facility has to wrestle with this question – what happens when the ‘release’ function throws? Silently swallowing the exception masks an API reporting failure that the application needs to know about, allowing the exception to propagate risks terminating the application if called as the consequence of unwinding another exception. There are no universal good answers, so allowing the destructor to throw, as one approach among many, seems reasonable.

    Of course, these examples are unlikely to be aggregated into other classes, but folks more familiar with throwing-destructor idioms will likely have better examples. I am happy to know the feature is there, works consistently, and never use it 🙂

    Reply

    1. Yeah there is a little discussion about throwing/failing cleanup functions in the comments of my last posts.

      Reply

  7. “While it necessarily a feature you should use on every class and every function you write, noexcept is worth keeping in mind….”

    Forgot “is not” after “it”.

    Reply

  8. Quick clarification on destructors – destructors are ‘noexcept’ (by default) if all of their bases and members have ‘noexcept’ destructors, and naturally that includes empty classes. You are correct that the destructor body is never examined, but if a member or base class has explicitly marked its destructor as ‘noexcept(false)’, then the derived/containing class will also have a ‘noexcept(false)’ destructor by default.

    Reply

    1. Thanks for the clarification! I’d consider declaring destructors as noexcept(false) to be highly questionable though.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *