libsq3  2007.10.18
Public Types | Public Member Functions | List of all members
refcount::rcptr< HandleT, FinalizerT > Class Template Reference

#include <refcount.hpp>

Public Types

typedef HandleT type
 The basic type of object pointed to.
 
typedef typepointer_type
 The basic pointer type.
 
typedef FinalizerT finalizer_type
 The type of functor used to clean up pointer_type objects. More...
 
typedef Detail::ref_type< type >::type reference_type
 reference_type is the same as (T&) unless T is void, in which case it is the same as (void*&) because (void&) is not legal.
 

Public Member Functions

 rcptr (pointer_type h)
 Transfers ownership of h, or allows h to participate in ownership with other rcptr objects pointing at h.
 
 rcptr (rcptr const &rhs)
 rhs and this object will both manage the same underlying pointer.
 
rcptroperator= (rcptr const &rhs)
 First disowns any connected pointer (using take(0)), then rhs and this object will both manage the same underlying pointer. More...
 
 rcptr ()
 An empty shared pointer, useful only as a target of assigment or take().
 
void swap (rcptr &rhs)
 Efficiently swaps this object and rhs, such that they swap ownership of their underlying pointers. More...
 
 ~rcptr ()
 See decrement();.
 
bool operator== (rcptr const &rhs) const
 Returns (this->m_ptr == rhs.m_ptr). More...
 
bool operator!= (rcptr const &rhs) const
 Returns (this->m_ptr != rhs.m_ptr). More...
 
bool operator< (rcptr const &rhs) const
 Returns this->get() < rhs.get(). More...
 
pointer_type get () const
 Returns this object's underlying pointer, which may be 0. More...
 
void take (pointer_type p)
 Gives ownership of p to this object (or a collection of like-types rcptr objects). More...
 
pointer_type take ()
 Transfers ownership of this->get() to the caller. More...
 
pointer_type operator-> () const
 The same as this->get().
 
reference_type operator * () const
 The same as *(this->get()). More...
 
size_t ref_count () const
 Returns the number of references to this object's pointer, or zero if no pointer is bound. More...
 
bool empty () const
 Returns the same as (!this->get()).
 

Detailed Description

template<typename HandleT, typename FinalizerT = plain_delete_finalizer>
class refcount::rcptr< HandleT, FinalizerT >

   A bare-bones non-intrusive reference-counted pointer type
   with the ability for the client to specify a
   finalization/destruction functor for the pointed-to type.

   HandleT must be a non-CVP-qualified type. As a special
   case, if HandleT is void then some code in this class will
   work a bit differently, notably the operator*(), because we
   cannot form a reference to void. Void is supported because
   (void *) is commonly used for opaque handles (e.g. libdl)
   or multibyte string pointers (e.g. libsqlite3).

   FinalizerT must be a type compatible with the
   plain_delete_finalizer interface. A default-constructed
   instance of that FinalizerT type will be created to
   "finalize" an object when the reference count for that
   object drops to zero. The exact behaviour of the FinalizerT
   is not specified here, but semantically it must "finalize"
   the object passed to it. The default finalizer simply
   deletes the object, whereas a more advanced finalizer might
   push the object into a garbage collection pool. For
   purposes of this class, after finalization of an object,
   client code (and this type) should no longer use the object
   - it is considered to be destroyed.

   This type does not currently have any built-in support for
   copy-on-write, so all copies are extremely shallow.

   Notes of Utmost Significance to Potential Users:

   - Implicit conversions to/from HandleT are not implemented
   after much deliberation on the subject. Clients will *have*
   to know they're using this class, as opposed to a plain
   pointer type. This is safest for everyone, IMO.

   - Don't mix plain and rcptr-hosted pointers, as the rcptr
   wrappers own the pointers and will clean them up, leaving
   any unadorned pointers dangling.

   - Thread safety: no special guarantees, along with lots of
   caveats and potential gotchas.

   - Don't mix different smart pointer types, not even
   rcptrs with the same HandleT type but different
   FinalizerT types. This will almost certainly bring about
   the incorrect finalization of a pointer.

   - The usage of a finalizer functor means that this type can
   be used with arbitrary types, regardless of whether the
   delete operation is legal or not on them. For example, the
   client code for which this class was written uses a functor
   to finalize sqlite3 database handles using the
   sqlite3_close() function.



   Design notes:

   - While originally based off of the presentation of
   rc-pointers in Meyers' "More Effective C++", Item 29, i
   believe his approach to storing the reference count in his
   RCIPtr class is flawed, as it allows multiple rc-pointers
   to delete the same pointer. Consider:
typedef RCIPtr<MyType> myPtrType;
MyType * t = new MyType;
myPtrType x(t);
myPtrType y(t);
   In theory, his presentation (admittedly 10+ years old now)
   would cause a double-delete for that case. In this model,
   that case is handled as if we had constructed y using y(x)
   instead of y(t), so both x and y share the reference count.

   - The reference count is stored in a static-space std::map,
   and that map is specific to this type and its combination
   of HandleT/FinalizerT types. If we made the map only
   specific to the HandleT, then we would get
   strange/undesired behaviour when we did:
rcptr<T1,finalizerT1> p1( new T1 );
rcptr<T2,finalizerT2> p2( p1.get() );
       because the actual finalizer used would be the one for
       which the rcptr is destroyed *last*. Since destruction
       order is not always determinate, this mixture would be a
       bad idea. Note that it is still illegal to add the same
       pointer to multiple different shared pointer types. The
       above example, while illegal, will at least cause
       determinate behaviour: a double finalization (but the order
   is still unspecified in the general case)!


   Fundamental differences between rcptr and
   boost::shared_ptr:

   - rcptr::take() allows client to take ownership of a
   pointer away from rcptr. According to the shared_ptr FAQ,
   this isn't technically feasible in that class due to their
   handling of the user-defined finalizer.

   - rcptr has no explicit support for multi-threading.

   - shared_ptr does not handle the following code "correctly"
   (IMO):

    typedef boost::shared_ptr<AStruct> SP;
    SP sp1( new AStruct );
    SP sp2( sp1.get() );

sp1.use_count() is 1, not 2 This causes a double deletion

    rcptr handles that case transparently.

Definition at line 217 of file refcount.hpp.

Member Typedef Documentation

◆ finalizer_type

template<typename HandleT, typename FinalizerT = plain_delete_finalizer>
typedef FinalizerT refcount::rcptr< HandleT, FinalizerT >::finalizer_type

The type of functor used to clean up pointer_type objects.

Definition at line 229 of file refcount.hpp.

Member Function Documentation

◆ get()

template<typename HandleT, typename FinalizerT = plain_delete_finalizer>
pointer_type refcount::rcptr< HandleT, FinalizerT >::get ( ) const
inline

Returns this object's underlying pointer, which may be 0.

This does not transfer ownership. This object still owns (or participates in the ownership of) the returned pointer.

Definition at line 385 of file refcount.hpp.

◆ operator *()

template<typename HandleT, typename FinalizerT = plain_delete_finalizer>
reference_type refcount::rcptr< HandleT, FinalizerT >::operator * ( ) const
inline

The same as *(this->get()).

Behaviour is undefined if (!this->get()). We would throw an exception, but this code is specifically intended for use on platforms where exceptions are not allowed or not supported (e.g. some embedded platforms).

SPECIAL CASE: rcptr::type is void

If rcptr::type is void then this function returns a refernce to a pointer instead of a reference. This is to allow this type to work with (void*) handle types, such as handles returned from dlopen() or memory returned from malloc(). Finalizers for such handles could call dlclose() or free(), as appropriate.

Definition at line 453 of file refcount.hpp.

◆ operator!=()

template<typename HandleT, typename FinalizerT = plain_delete_finalizer>
bool refcount::rcptr< HandleT, FinalizerT >::operator!= ( rcptr< HandleT, FinalizerT > const &  rhs) const
inline

Returns (this->m_ptr != rhs.m_ptr).

Definition at line 366 of file refcount.hpp.

◆ operator<()

template<typename HandleT, typename FinalizerT = plain_delete_finalizer>
bool refcount::rcptr< HandleT, FinalizerT >::operator< ( rcptr< HandleT, FinalizerT > const &  rhs) const
inline

Returns this->get() < rhs.get().

Implemented so that this type can be used as keys in STL containers.

Definition at line 375 of file refcount.hpp.

◆ operator=()

template<typename HandleT, typename FinalizerT = plain_delete_finalizer>
rcptr& refcount::rcptr< HandleT, FinalizerT >::operator= ( rcptr< HandleT, FinalizerT > const &  rhs)
inline

First disowns any connected pointer (using take(0)), then rhs and this object will both manage the same underlying pointer.

If by chance rhs.get() == this->get() when this function starts then this function does nothing and has no side effects.

Definition at line 319 of file refcount.hpp.

◆ operator==()

template<typename HandleT, typename FinalizerT = plain_delete_finalizer>
bool refcount::rcptr< HandleT, FinalizerT >::operator== ( rcptr< HandleT, FinalizerT > const &  rhs) const
inline

Returns (this->m_ptr == rhs.m_ptr).

Definition at line 361 of file refcount.hpp.

◆ ref_count()

template<typename HandleT, typename FinalizerT = plain_delete_finalizer>
size_t refcount::rcptr< HandleT, FinalizerT >::ref_count ( ) const
inline

Returns the number of references to this object's pointer, or zero if no pointer is bound.

This function should be considered a debugging/informational function, and not a "feature" of this type.

Complexity = that of a std::map lookup.

Definition at line 465 of file refcount.hpp.

◆ swap()

template<typename HandleT, typename FinalizerT = plain_delete_finalizer>
void refcount::rcptr< HandleT, FinalizerT >::swap ( rcptr< HandleT, FinalizerT > &  rhs)
inline

Efficiently swaps this object and rhs, such that they swap ownership of their underlying pointers.

This does not require fiddling with the reference counts, so it is much faster than using an rcptr copy to perform a swap.

Definition at line 341 of file refcount.hpp.

◆ take() [1/2]

template<typename HandleT, typename FinalizerT = plain_delete_finalizer>
void refcount::rcptr< HandleT, FinalizerT >::take ( pointer_type  p)
inline

Gives ownership of p to this object (or a collection of like-types rcptr objects).

Drops ownership of this->get() before making the takeover. If (this->get() == p) then this function does nothing.

Definition at line 394 of file refcount.hpp.

◆ take() [2/2]

template<typename HandleT, typename FinalizerT = plain_delete_finalizer>
pointer_type refcount::rcptr< HandleT, FinalizerT >::take ( )
inline

Transfers ownership of this->get() to the caller.

ALL rcptr<> objects which point to that object (except this rcptr) STILL point to that object, but they will not activate the destructor functor when they die, so they are safe as long as they remain unsued or are destroyed before the "raw" pointer returned from this function is destroyed.

Definition at line 411 of file refcount.hpp.


The documentation for this class was generated from the following file: