Boost logo

Boost :

From: David Abrahams (david.abrahams_at_[hidden])
Date: 2001-06-16 14:21:20


----- Original Message -----
From: "Vesa Karvonen" <vesa.karvonen_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Saturday, June 16, 2001 8:55 AM
Subject: [boost] Stronger exception safety guarantee for smart_ptr.reset()

> 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

Not in my experience, FWIW.

> , because a destructor
> may involve an arbitrarily complex computation and may, in particular,
> call functions that are not destructors.

Most destructor bodies I write, however, are empty. I think that has become
an expectation among modern C++ programmers. It's fairly easy to follow the
rule, "if you write a non-empty destructor body, consider what exceptions
may be thrown".

> 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.

From a standards POV, I think this change would be a mistake.
auto_ptr<T>::reset() is currently guaranteed not to throw an exception.
Unless you remove that guarantee or swallow exceptions thrown by T (either
one IMO a very bad idea), it is meaningless to talk about what happens if T
throws.

> 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.

From an implementation POV, I'm not /opposed/ to the above as a way of
providing better quality... but I'm not convinced it adds quality without
accompanying guarantees from the standard. Since I don't think we can/should
make those, for reasons previously outlined, I am at best lukewarm to this
idea.

-Dave


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