Boost logo

Boost :

Subject: [boost] [ptr_container] Questionable strong guarantee of ptr_map::insert()
From: Kazutoshi Satoda (k_satoda_at_[hidden])
Date: 2009-08-17 16:27:08


With current implementation of ptr_map::insert(), if an exception is
thrown, the objected pointed by the passed pointer is deleted. Is this
really providing strong guarantee as documented?

I understand strong guarantee as described here.
> The strong guarantee: that the operation has either completed
> successfully or thrown an exception, leaving the program state exactly
> as it was before the operation started.
I think ptr_map::insert() doesn't provide this guarantee because
deleting the object is a change of the program state.

As more concrete problem, see the attached code. I couldn't find any
way to provide strong guarantee for delayed_inserter::insert_ready()
using ptr_map. I want ready_value unchanged if an exception is thrown
during the insertion.

Looking for a solution on a similar situation, I found constructors of
shared_ptr. Its documentation clearly says that "If an exception is
thrown, delete p is called". And for auto_ptr version, it provides
strong guarantee by taking the auto_ptr as non-const reference.

I think ptr_map::insert() should follow this manner; document the
deletion on exception for raw pointer version, and provide strong
guarantee with insert(const key_type& key, std::auto_ptr<U>& x) .

The the auto_ptr& version can be a better replacement of the raw pointer
version. The required temporary of auto_ptr, instead of key_type, is
more expressive (about the purpose of the temporary), and matches the
Best Practices shown in the documentation of shared_ptr.

But, introducing the auto_ptr& version seems to cause some change of
behavior in client codes using the current pass-by-value version. Is it
valid to request (create a ticket) for strong guaranteed (taking
auto_ptr&) version while having this compatibility concern?



#include <memory>
#include "boost/ptr_container/ptr_map.hpp"

namespace ptr_map_insert_strong_guarantee_demo {

class value
  explicit value(int source);
  // ...

class delayed_inserter
  // ...

  // This is called from context that knows key and source of value,
  // but doesn't know the time of insertion.
  void ready_new(int key, int source)
    // OK.
    // This implementation offers strong guarantee for this call.
    std::auto_ptr<value> new_value(new value(source));
    ready_key = key;
    ready_value = new_value;

  // This is called from context which doesn't know key and value,
  // but knows the time of insertion.
  void insert_ready()
    if (ready_value.get() != 0)
      // I want to offer strong guarantee for this call,
      // but boost::ptr_map deosn't provide the way to do that;
      // *** ready_value is deleted when an exception is thrown. ***
      map.insert(ready_key, ready_value);

  // ...
  int ready_key;
  std::auto_ptr<value> ready_value;
  boost::ptr_map<int, value> map;
  // ...


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