Exception safety guarantees, originally formalized by David Abrahams, are a set of contractual guidelines that class library implementers and clients can use when reasoning about exception handling safety in any programming language that uses exceptions, particularly C++.
There are several levels of exception safety (in decreasing order of safety):
- No-throw guarantee, also known as failure transparency: Operations are guaranteed to succeed and satisfy all requirements even in exceptional situations. If an exception occurs, it will be handled internally and not observed by clients.
- Strong exception safety, also known as commit or rollback semantics: Operations can fail, but failed operations are guaranteed to have no side effects, so all data retain their original values.
- Basic exception safety, also known as a no-leak guarantee: Partial execution of failed operations can cause side effects, but all invariants are preserved and there are no resource leaks (including memory leaks). Any stored data will contain valid values, even if they differ from what they were before the exception.
- No exception safety: No guarantees are made.
Usually, at least basic exception safety is required to write robust code in such languages. Higher levels of safety can sometimes be difficult to achieve, and might incur an overhead due to extra copying. A key mechanism for exception safety is a
finally clause, or similar exception handling syntax, which ensure that certain code is always run when a block is exited, including by exceptions. Several languages have constructs that simplify this, notably using the dispose pattern, named as
Consider a smart vector type, such as C++'s
std::vector or Java's
ArrayList. When an item
x is added to a vector
v, the vector must actually add
x to the internal list of objects and update a count field that says how many objects are in
v. It may also need to allocate new memory if the existing capacity isn't sufficient.
Exception safety alternatives:
- No-throw guarantee
- Very difficult or impossible to implement, since memory allocation may fail and throw an exception. Handling allocation failure would then be problematic, since repeated attempts are also likely to fail.
- Strong exception safety
- Can be implemented fairly easily by doing any allocation first and then copying into a temporary buffer that is eventually swapped if no errors are encountered. In this case, insertion of
vwill either succeed, or
vwill remain unchanged.
- Basic exception safety
- Implemented by ensuring that the size field is guaranteed to be updated if
xis successfully inserted. Also, all allocations need to be handled in a way that prevents any chance of a resource leak, regardless of failure.
- No exception safety
- Implementation in which an insertion failure might lead to corrupted content in
v, an incorrect size value, or a resource leak.
- "Exception-Safety in Generic Components". Retrieved 2008-08-29.
- Abrahams, D. (2000). Exception-Safety in Generic Components. Generic Programming. LNCS. 1766. Springer. pp. 69–79. doi:10.1007/3-540-39953-4_6. ISBN 978-3-540-41090-4.
- Bjarne Stroustrup. "Appendix E: Standard-Library Exception Safety in "The C++ Programming Language" (3rd Edition).Addison-Wesley, ISBN 0-201-88954-4" (PDF).