Channels ▼

Andrew Koenig

Dr. Dobb's Bloggers

Object Swapping, Part 6: Exception Safety

April 18, 2012

So far we have been talking mostly about using swap operations to make assignment, copying, and moving objects more convenient and faster. Swapping also has an important role to play in making such operations exception safe.

More Insights

White Papers

More >>

Reports

More >>

Webcasts

More >>

The term "exception safety" has different meanings in different contexts, but it generally refers to the idea of being confident about what will — or won't — have been done if an operation ends in an exception. It is particularly nice to be able to make a "strong exception safety guarantee" about an operation: Your operation will run to completion or not at all. For example, if you add an object to a collection, it is nice to be able to know that either the object will be successfully added to the collection or an exception will result, and if the exception does happen, everything will be in the same state afterward that it was in before you started.

Suppose that we want to write a function that implements a strong exception safety guarantee: It does either everything that was asked of it or nothing at all. How do we go about it? The problem becomes tricky when our function has several things to do, because if we do some of them, and then an exception occurs, we have to remember what we did so that we can undo it correctly. Moreover, it has to be possible to undo what we did. This requirement means that we must not do anything irrevocable until it is no longer possible for our function to throw an exception.

Exceptions usually come from trying to use more resources than are available. For example, copying data can throw an exception if memory (or another resource) is needed for the copy. In contrast, it is considered very bad manners to throw an exception as part of releasing a resource.

These requirements suggest a general strategy for implementing any function that we wish to be exception safe:

  1. Do all of the work that might possibly throw an exception, saving the results of that work where it can be backed out safely.
  2. Once it is no longer possible to throw an exception, put the results of (1) in their proper place.

The easiest way of putting results where they can be backed out is to store them in local variables. Such variables will be destroyed automatically if an exception occurs, so we can often structure our programs so as to make it unnecessary to worry about exceptions at all during phase 1.

We are then left with phase 2, and it is here that swapping becomes important. The point is that swapping can usually be implemented in a way that precludes exceptions. If we swap a local variable with the destination of our computation, then not only do we not have to worry about an exception that might happen during the computation, but we also do not have to worry about freeing the data that we are overwriting. Those data are now in the local variable, and when our function exits, that variable will be freed automatically.

Let's see how this strategy fits the copy-and-swap strategy for implementing assignment:

 
Thing& operator=(Thing t) {
       swap(t);
       return *this;
}

When we call operator=, our argument is copied to the parameter t. This operation may allocate resources, so it might throw an exception — but we don't care. All we are doing is creating a local variable (namely t); so if an exception does occur, that variable will be destroyed automatically. Once we get into the body of our function, exceptions are no longer possible — so long as the call to swap cannot throw an exception. The return statement doesn't do anything that might throw an exception. When operator= returns, it will destroy the former value of *this.

In effect, phase 2 of our two-phase process begins with the call to swap. The work we were doing until this point might have thrown an exception, but we haven't done anything irrevocable yet. The work we do after this point does change the program's state, but exceptions can no longer occur. The ability to swap objects' contents without throwing an exception is the glue that holds this whole strategy together.

Related Reading






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 


Video