Embedded reference count with Boost shared_ptr

2019-06-07 19:26发布

I love Boost's smart_ptr features and the ability to convert to and from a shared_ptr and weak_ptr, but since the reference count is not contained in the pointed class itself, the following code does not work (and it shouldn't).

A *a = new A;
shared_ptr<A> aPtr1(a);

{
    shared_ptr<A> aPtr2(a);

    // The reference counts of aPtr1 and aPtr2 are both 1.
}   // At this point, `a` is destructed by aPtr2.

aPtr1->foo();   // And... SIGTERM

I believe the JUCE framework has this functionality. [ReferenceCountedObject and ReferenceCountedObjectPtr] However, I'd rather use Boost for my application. Is it possible to allow Boost smart_ptrs to look for the reference count in the pointed class rather than the private boost::detail::shared_count instance?

3条回答
Explosion°爆炸
2楼-- · 2019-06-07 19:45

This is not exception safe:

// call this as in shared_ptr<T> foo = create_intrusive_shared( new T(blah) );
// This takes ownership of the pointer you pass it.
template<typename T>
std::shared_ptr<T> create_intrusive_shared( T* t )
{
  auto retval = std::shared_ptr<T>( t, []( T* cleanup )
  {
    if (cleanup)
      cleanup->RemoveRef();
  });
  return retval;
}

// Call this if you have an existing instance of T, whose ownership is being
// maintained elsewhere.  Do not call it with new T() as an argument, unless
// new instances of T are created with a 0 ref count
template<typename T>
std::shared_ptr<T> make_intrusive_shared( T* t )
{
  if (t)
    t->AddRef();
  auto retval = create_intrusive_shared(t);
  return retval;
}

Making them exception safe takes a bit more work. You will want to reimplement make_shared, but tag the resulting shared_ptr with a cleanup function.

查看更多
混吃等死
3楼-- · 2019-06-07 19:59

Simple solution:

A *a = new A;
shared_ptr<A> aPtr1(a);
{
    // construct new shared pointer from old one.
    shared_ptr<A> aPtr2(aPtr1);
}
aPtr1->foo();

If you want something more complicated, see http://www.boost.org/libs/smart_ptr/enable_shared_from_this.html :

The header <boost/enable_shared_from_this.hpp> defines the class template enable_shared_from_this. It is used as a base class that allows a shared_ptr to the current object to be obtained from within a member function.


Edit: I should have mentioned that enable_shared_from_this has some unfortunate issues with derivation. However, the following works with c++11; I didn't try it with boost but I suppose it should work there, too. I think it's a bit of a hack; using raw pointers when you use shared_ptr's is bound to end in tears:

struct X : std::enable_shared_from_this {
  /* stuff */
};

struct Y : X {
  /* stuff */
  void yonly() {};
};

int main() {
  Y* y = new Y;
  shared_ptr<Y> sy(y);
  sy->yonly();
  {
    auto sy2 = std::shared_ptr<Y>(y->shared_from_this(), y);
    sy2->yonly();
  } 
  std::cout << "Block ended" << std::endl;
  return 0;
} 
查看更多
神经病院院长
4楼-- · 2019-06-07 20:11

boost::intrusive_ptr likely fits your requirements.

To note however, with shared_ptr, you should construct them as follows:

shared_ptr<A> aPtr1 = boost::make_shared<A>();
查看更多
登录 后发表回答