Boost logo

Boost :

From: Peter Dimov (pdimov_at_[hidden])
Date: 2005-02-11 17:33:25

Daniel James wrote:
> Hello everyone,
> I've got an exception safety problem implementing the hash containers.
> The draft standard says (from
> 'For unordered associative containers, no swap function throws an
> exception unless that exception is thrown by the copy constructor or
> copy assignment operator of the container's Hash or [equality] Pred
> object (if any).'
> This is a problem, because for the container to be valid, its hash
> buckets, equality predicate and hash function need to consistent.
> Since
> both the hash and predicate can throw, this is impossible (or hard?)
> to achieve. If swapping/copying the first one succeeds, and the
> second one throws they won't match. Any ideas on what I should do?
> I don't think this can cause any major problems, like memory leaks or
> access to unowned memory, but it can cause unpredictable behaviour -
> since equal keys can end up in different buckets. Basically the
> invariant ends up totally broken.
> The only solution that I've come up with, is to store the two function
> objects in a seperate structure, allocated on the heap, so that only
> pointers have to be swapped. But this seems unfortunate since most
> function objects won't throw.

Another option is to double-buffer the hash function and the predicate.

Hash hash_[ 2 ];
Pred pred_[ 2 ];

int which_;

void swap( this_type & rhs )
    using std::swap;

    hash_[ !which_ ] = rhs.hash_[ rhs.which_ ];
    pred_[ !which_ ] = rhs.pred_[ rhs.which_ ];
    rhs.hash_[ !rhs.which_ ] = hash_[ which_ ];
    rhs.pred_[ !rhs.which_ ] = pred_[ which_ ];

    // do other things that may fail

    // commit

    which_ = !which_;
    rhs.which_ = !rhs.which_;

or something like that. Untested.

Boost list run by bdawes at, gregod at, cpdaniel at, john at