From: Bronek Kozicki (brok_at_[hidden])
Date: 2004-01-15 05:24:23


On Wed, 14 Jan 2004 16:46:25 -0800 (PST), Sean Kelly wrote:
> Currently, there's no way to force a shared_ptr to release something once
> it has been given ownership of it. I've run into instances where I use a

There is a way, and I will show you how I did it in my production code
(single-threaded at this moment, but I think you will have no trouble to
make it concurrency-safe).

class node : public boost::noncopyable // plus some more parent classes
{
private:
  struct deleter
  {
    bool released;

    deleter() : released(false) {}

    void operator() (node* p)
    {
      if (!released)
        delete p;
    }
  };
  
  friend class std::auto_ptr<node>;
  friend void boost::checked_delete<node>(node* x);

  typedef std::vector<boost::shared_ptr<node> > children_collection;

  children_collection children2_;
  node* parent_;
// ...

public:
  std::auto_ptr<node> remove()
  {
    // ...
    boost::shared_ptr<node> me;
    {
      children_collection children2;
      for (children_collection::const_iterator ci =
parent_->children2_.begin(); ci != parent_->children2_.end(); ++ci)
      {
        // simplified, real production code is different
        if (ci->get() != this)
          children2.push_back(*ci);
        else
          me = (*ci);
      }

      parent_->children2_.swap(children2);
    }

    std::auto_ptr<node> me2;
    {
      // you would lock critical section or mutex here, and such
      // synchronization primitive could be stored inside deleter
      assert(me.unique());
      me2.reset(me.get());
      boost::get_deleter<deleter>(me)->released = true;
      me.reset();
    }

    return me2;
  }
}

It's bit complicated and I'm not happy with it, but it works and seems
to be reliable

B.