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( <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.

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.

Facebooktwittergoogle_plusredditlinkedinFacebooktwittergoogle_plusredditlinkedinby feather

13 Comments

  1. S.Clem

    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

  2. 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. Arne Mertz

      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
  3. SeattleC++

    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
  4. SeattleC++

    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. Andreas

      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. Indranil

      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
  5. AlisdairM

    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. Arne Mertz

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

      Reply
  6. emel

    “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
  7. AlisdairM

    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. Arne Mertz

      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 *