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?
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;
}
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>();
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.