Boost logo

Boost :

From: Vesa Karvonen (vesa.karvonen_at_[hidden])
Date: 2001-06-16 07:55:04


The Boost smart pointer exception safety considerations are carefully
crafted, however there is at least one issue that IMO requires further
consideration. This issue is the exception safety guarantee of reset()
(and possibly other similar operations).

The following discussion is mostly in terms of auto_ptr<> and the standard
library, however the issue generalizes to other smart pointer and resource
designs.

In the C++ standard library, as well as in Boost, there is a requirement
that objects may not throw in destructors. Unfortunately this is very
difficult to ensure both in theory and in practice, because a destructor
may involve an arbitrarily complex computation and may, in particular,
call functions that are not destructors. Therefore resource management
primitives, such as auto_ptr<>, whose purpose is to guarantee orderly
release of resources, should aim to ensure meaningful operation even when
the resource release operation, such as deletion of an object, might
occasionally throw an exception.

Consider the following code:

  auto_ptr<may_throw> ap(new may_throw);

  ap.reset(new may_throw);

According to the C++ standard, the behavior of the reset() operation in
the above code snippet is undefined if deletion of the may_throw object
throws an exception. In particular, the newly allocated object, to which
there is no pointer anymore, may or may not get assigned to the auto_ptr
and therefore might become a memory leak.

A stronger guarantee, in which the assignment of the pointer to the smart
pointer would be guaranteed, would be arguably safer. It is also important
to note, that such a guarantee would not sacrifice any current behavior,
because the behavior is currently undefined.

The deletion of the newly allocated object can be guaranteed easily by
using a variation of the swap-idiom for exception safety:

  template<class T>
  void auto_ptr<T>::reset(T* new_p)
  { // short circuit self-assignment
    if (this_p == new_p)
      return;

    // swap (performed here only partially)
    T* old_p = this_p;
    this_p = new_p;

    // perform operations that might throw
    delete old_p;
  }

The run-time overhead of the above technique, compared to the traditional
implementation, should be for all intents and purposes negligible.

The above technique can be generalized to other smart pointers and more
general resources management primitives.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk