intrusive_ptr
Header: "boost/intrusive_ptr.hpp"
intrusive_ptr is the intrusive analogue to shared_ptr. Sometimes, there's no other
choice than using an intrusive, reference-counted smart pointer. The typical
scenario is for code that has already been written with an internal reference
counter, and where there's no time to rewrite it (or where the code's not available).
Another case is when the size of a smart pointer must be exactly the size of a raw
pointer, or when performance is hurt by the allocation of the reference count for
shared_ptr (a rare case, I'm sure!). The only case where it would seem that an
intrusive smart pointer is required, from a functional perspective, is when a
member function of a pointed-to class needs to return this, such that it can be used
in another smart pointer. (Actually, there are ways to solve that problem with non-
intrusive smart pointers too, as we saw earlier in this chapter.) intrusive_ptr is
different from the other smart pointers because it requires you to provide the
reference counter that it manipulates.
When intrusive_ptr increments or decrements a reference count on a non-null
pointer, it does so by making unqualified calls to the functions
intrusive_ptr_add_ref and intrusive_ptr_release, respectively. These functions are
responsible for making sure that the reference count is always correct and, if the
reference counter drops to zero, to delete the pointer. Therefore, you must overload
those functions for your type, as we shall see later.
This is a partial synopsis for intrusive_ptr, showing the most important functions.
namespace boost {
template<class T> class intrusive_ptr {
public:
intrusive_ptr(T* p,bool add_ref=true);
intrusive_ptr(const intrusive_ptr& r);
~intrusive_ptr();
T& operator*() const;
T* operator->() const;
T* get() const;
This member function returns the stored pointer. It can be used when a raw pointer
is needed, and may be called even when the stored pointer is null. This function
never throws.
operator unspecified-bool-type() const;
This conversion function returns a type that can be used in Boolean expressions,
but it is not operator bool, because that would allow for other operations that
should be prohibited. The conversion allows intrusive_ptr to be tested in Boolean
contextsfor example, if (p), with p being an instance of intrusive_ptr. The returned
value is TRue if the intrusive_ptr references a non-null pointer; otherwise, it
returns false. This conversion function never throws.
Free Functions
template <class T> T* get_pointer(const intrusive_ptr<T>& p);
The function returns p.get(), and its purpose is mainly to support generic
programming.
[10]
It may also be used as a coding convention instead of calling the
member function get, because it can be overloaded to work with raw pointers and
third-party smart pointer classes. Some simply prefer calling a free function over
accessing a member function.
[11]
The function never throws.
[10]
Such functions are known as shims. See [12] in the Bibliography.
[11]
The idea is that the line between operating on the smart pointer and operating
on what it points to can be blurred when using smart pointer member functions.
For example, p.get() and p->get() have completely different meanings and can be a
little difficult to distinguish at a glance, whereas get_pointer(p) and p->get() look
nothing alike. Whether that's a problem for you is a matter of taste and experience.
template <class T,class U>
delete t;
}
Note that these functions should be defined in the scope of their argument types.
This means that if this function is called with arguments from a namespace, the
functions should be defined there, too. The reason for this is that the calls are
unqualified, which means that argument-dependent lookup is permitted, and there
may be cases where more than one version of these functions must be provided,
which makes the global namespace a bad place to put them. We'll see an example
of where to place these functions later, but first, we need to provide some sort of
internal reference counter.
Providing a Reference Counter
Now that the management functions have been defined, we must provide an
internal reference count. In this example, the reference count is a private data
member that's initialized to zero, and we'll expose add_ref and release member
functions to manipulate it. add_ref increments the reference count and release
decrements it.
[13]
We could add a third member function to return the current value
of the reference count, but it suffices to have release return it. The following base
class, reference_counter, provides a counter and the add_ref and release member
functions, making adding reference counting to a class as easy as using inheritance.
[13]
Note that in a multithreaded environment, any operation on the variable holding
the reference count needs to be synchronized.
class reference_counter {
int ref_count_;
public:
reference_counter() : ref_count_(0) {}
virtual ~reference_counter() {}