C++ Exception Safety Guarantee

After stumbling on this one in a recent telephone interview, I thought I’d refresh my memory.

The following from Anthony Williams’s ACCU Overload Journal article last August provides a succinct summary of the topic.

The Abrahams Exception Safety Guarantee

These guarantees were first documented by Dave Abrahams when the C++ Standards committee were working on the 1998 C++ Standard. The idea is that code should provide one of the three guarantees – if it doesn’t, then an exception occuring in your code will result in leaked resources or corrupt data structures or both. The guarantees are:

The no-fail (or no-throw) guarantee

This is the strongest of all guarantees. A function that provides this guarantee will not throw any exceptions, and will not fail. All destructors should provide this guarantee, as should important operations like swap which provide the building blocks for the code that uses them to provide suitable exception safety guarantees.

The strong guarantee

A function that provides this guarantee is all or nothing: if it fails, then any effects are rolled back so the state of the data structure is the same as it was on entry. This requires that the function doesn’t do anything irreversible (like perform I/O), and that there are suitable operations that provide the no-fail guarantee which can be used to commit or roll back the changes.

The basic guarantee

This is the basic level you should strive for in all code: if a function fails, then it must leave the data structures in a valid state, even if that state differs from the original. For example, failure to insert a new item into a container must leave the container in a valid state, even if all the existing items have been deleted.

Any code that doesn’t provide even the basic guarantee is not exception safe.

Exceptions Make for Elegant Code, ACCU Overload Journal #86, August 2008

Writing exception safe code is hard. If you have any doubts about that statement consider the following challenge from Herb Sutter: Guru of the Week 8. In Exceptional C++, Sutter expands on his earlier post and provides the following guidelines –

Observe the canonical exception-safety rules: (1) Never allow an exception to escape from a destructor or from an overloaded operator delete() or operator delete[](); write every destructor and deallocation function as though it had an exception specification of “throw()“. (2) Always use the “resource acquisition is initialization” idiom to isolate resource ownership and management. (3) In each function, take all the code that might emit an exception and do all that work safely off to the side. Only then, when you know that the real work has succeeded, should you modify the program state (and clean up) using only nonthrowing operations.

The standard for the C++ Standard Library contains the guarantee that no destructor operation defined in the library itself will throw an exception. The C++ Standard, however, does not enforce this requirement for all C++ code so your compiler will not prevent you from creating a class that breaks the golden rule: never throw exceptions from a destructor.

Anyone looking for more information should consult the links above and also look at Abrahams’s essay: Exception-Safety in Generic Components: Lessons Learned from Specifying Exception-Safety for the C++ Standard Library.

2 Responses to “C++ Exception Safety Guarantee”

  1. Mike Arthur says:

    I find the safest way to use exceptions in C++ is to not do so!

    I’m a former Java monkey so I miss the strictness of the exception model in Java, in my opinion a much more sensible way of doing things because you actually have some indicator in your code of when it might decide to randomly leap up the stack.

    Good post thought, interesting stuff!

  2. Tim Hardy says:

    Too true, Mike. The exception mechanism helps clarify the intention of code by making it easier to separate error handling code from regular execution code but it also introduces a whole new level of complexity that sometimes might best be avoided.