Exception safety
Exception safety guarantees, originally formalized by David Abrahams,[1][2] are a set of contractual guidelines that 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):[3]
- 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, leaving the original values intact.[4]
- Basic exception safety, also known as a no-leak guarantee: Partial execution of failed operations can result in side effects, but all invariants are preserved and there are no resource leaks (including memory leaks). Any stored data will contain valid values which may differ from the original values.
- 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 using
, with
, or try
-with-resources.
Example
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
- Implemented by ensuring that memory allocation never fails, or by defining the
insert
function's behavior on allocation failure (for example, by having the function return a boolean result indicating whether the insertion took place). - Strong exception safety
- Implemented by doing any necessary allocation first, and then swapping buffers if no errors are encountered (the copy-and-swap idiom). In this case, either the insertion of
x
intov
succeeds, orv
remains unchanged despite the allocation failure. - Basic exception safety
- Implemented by ensuring that the count field is guaranteed to reflect the final size of
v
. For example, if an error is encountered, theinsert
function might completely deallocatev
and reset its count field to zero. On failure, no resources are leaked, butv
's old value is not preserved. - No exception safety
- An insertion failure might lead to corrupted content in
v
, an incorrect value in the count field, or a resource leak.
References
- David Abrahams. "Exception-Safety in Generic Components". Retrieved 2008-08-29.
- Dave Abrahams (2000). Exception-Safety in Generic Components. Generic Programming. Lecture Notes in Computer Science. 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 ed.). Addison-Wesley. ISBN 0-201-88954-4. Missing or empty
|url=
(help) - http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1997/N1077.asc
External links
- Herb Sutter: Exceptional C++: 47 Engineering Puzzles, Programming Problems, and Solutions, 2000
- Jon Kalb: Exception-Safe Coding in C++, with C++Now! 2012 presentations on exception safety.
- Related discussion on Stackoverflow: C++: do you (really) write exception safe code