c++-gtk-utils
intrusive_ptr.h
Go to the documentation of this file.
00001 /* Copyright (C) 2006, 2009 and 2011 Chris Vine
00002 
00003 The library comprised in this file or of which this file is part is
00004 distributed by Chris Vine under the GNU Lesser General Public
00005 License as follows:
00006 
00007    This library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Lesser General Public License
00009    as published by the Free Software Foundation; either version 2.1 of
00010    the License, or (at your option) any later version.
00011 
00012    This library is distributed in the hope that it will be useful, but
00013    WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Lesser General Public License, version 2.1, for more details.
00016 
00017    You should have received a copy of the GNU Lesser General Public
00018    License, version 2.1, along with this library (see the file LGPL.TXT
00019    which came with this source code package in the c++-gtk-utils
00020    sub-directory); if not, write to the Free Software Foundation, Inc.,
00021    59 Temple Place - Suite 330, Boston, MA, 02111-1307, USA.
00022 
00023 However, it is not intended that the object code of a program whose
00024 source code instantiates a template from this file or uses macros or
00025 inline functions (of any length) should by reason only of that
00026 instantiation or use be subject to the restrictions of use in the GNU
00027 Lesser General Public License.  With that in mind, the words "and
00028 macros, inline functions and instantiations of templates (of any
00029 length)" shall be treated as substituted for the words "and small
00030 macros and small inline functions (ten lines or less in length)" in
00031 the fourth paragraph of section 5 of that licence.  This does not
00032 affect any other reason why object code may be subject to the
00033 restrictions in that licence (nor for the avoidance of doubt does it
00034 affect the application of section 2 of that licence to modifications
00035 of the source code in this file).
00036 
00037 */
00038 
00039 #ifndef CGU_INTRUSIVE_PTR_H
00040 #define CGU_INTRUSIVE_PTR_H
00041 
00042 // define this if, instead of GLIB atomic funcions/memory barriers,
00043 // you want to use a (slower) mutex to lock the reference count in the
00044 // IntrusiveLockCounter class (however, if wanted, this is best left for
00045 // definition in the user code)
00046 /* #define CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX 1 */
00047 
00048 #include <utility>    // for std::move and std::swap
00049 #include <functional> // for std::less and std::hash<T*>
00050 #include <cstddef>    // for std::size_t
00051 
00052 #ifdef CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX
00053 #include <c++-gtk-utils/mutex.h>
00054 #else
00055 #include <glib.h>
00056 #endif
00057 
00058 #include <c++-gtk-utils/cgu_config.h>
00059 
00060 /**
00061  * @addtogroup handles handles and smart pointers
00062  */
00063 
00064 namespace Cgu {
00065 
00066 /**
00067  * @class IntrusivePtr intrusive_ptr.h c++-gtk-utils/intrusive_ptr.h
00068  * @brief This is a smart pointer for managing objects allocated on
00069  * freestore which maintain their own reference count.
00070  * @ingroup handles
00071  *
00072  * @details This is a class which manages objects which maintain their
00073  * own reference count.  It requires that the referenced object has
00074  * two functions called ref() and unref(), which increment and
00075  * decrement the reference count respectively.  The IntrusiveCounter
00076  * or IntrusiveLockCounter class can be inherited from to do this, but
00077  * they do not have to be used.  The IntrusiveLockCounter class is the
00078  * same as the IntrusiveCounter class, except that it locks the
00079  * reference count when it is incremented or decremented in order that
00080  * IntrusivePtr objects in different threads can access the same
00081  * object.  (But only the reference count is locked, not the methods
00082  * of the referenced object.)
00083  *
00084  * All the constructors (including the constructor which takes a raw
00085  * pointer) increment the reference count, and the destructor
00086  * decrements it and expects the referenced object to be deleted when
00087  * the last IntrusivePtr referencing a particular object is destroyed.
00088  * The IntrusiveCounter and IntrusiveLockCounter classes behave in
00089  * this way.  (This is different from the behaviour of GobjHandle
00090  * smart pointers, which are constrained by the GObject reference
00091  * counting system which begins with a reference count of 1 rather
00092  * than 0, and of course different from normal shared pointer
00093  * implementations for the same reason.  The advantage of the approach
00094  * with IntrusivePtr is that an already-managed object may safely be
00095  * passed to the constructor taking a raw pointer without any
00096  * additional steps being necessary.)
00097  */
00098 
00099 template <class T> class IntrusivePtr {
00100 
00101   T* obj_p;
00102 
00103   void unreference() {
00104     if (obj_p) obj_p->unref();
00105   }
00106 
00107   void reference() {
00108     if (obj_p) obj_p->ref();
00109   }
00110 
00111 public:
00112  /**
00113   * This constructor does not throw.
00114   * @param ptr The object which the IntrusivePtr is to manage (if
00115   * any).
00116   */
00117   explicit IntrusivePtr(T* ptr = 0) {
00118     obj_p = ptr;
00119     reference();
00120   }
00121 
00122  /**
00123   * This copy constructor does not throw.
00124   * @param intr_ptr The intrusive pointer to be copied.
00125   */
00126   IntrusivePtr(const IntrusivePtr& intr_ptr) {
00127     obj_p = intr_ptr.obj_p;
00128     reference();
00129   }
00130 
00131  /**
00132   * The move constructor does not throw.  It has move semantics.
00133   * @param intr_ptr The instrusive pointer to be moved.
00134   */
00135   IntrusivePtr(IntrusivePtr&& intr_ptr) {
00136     obj_p = intr_ptr.obj_p;
00137     intr_ptr.obj_p = 0;
00138   }
00139 
00140   template <class U> friend class IntrusivePtr;
00141 
00142  /**
00143   * A version of the copy constructor which enables pointer type
00144   * conversion (assuming the type passed is implicitly type
00145   * convertible to the managed type, such as a derived type).  This
00146   * copy constructor does not throw.
00147   * @param intr_ptr The intrusive pointer to be copied.
00148   */
00149   template <class U> IntrusivePtr(const IntrusivePtr<U>& intr_ptr) {
00150     obj_p = intr_ptr.obj_p;
00151     reference();
00152   }
00153 
00154  /**
00155   * A version of the move constructor which enables pointer type
00156   * conversion (assuming the type passed is implicitly type
00157   * convertible to the managed type, such as a derived type).  This
00158   * move constructor does not throw.
00159   * @param intr_ptr The intrusive pointer to be moved.
00160   */
00161   template <class U> IntrusivePtr(IntrusivePtr<U>&& intr_ptr) {
00162     obj_p = intr_ptr.obj_p;
00163     intr_ptr.obj_p = 0;
00164   }
00165 
00166  /**
00167   * This method (and so copy or move assignment) does not throw unless
00168   * the destructor of a managed object throws.
00169   * @param intr_ptr The assignee.
00170   * @return The IntrusivePtr object after assignment.
00171   */
00172   // having a value type as the argument, rather than reference to const
00173   // and then initialising a tmp object, gives the compiler more scope
00174   // for optimisation, and also caters for r-values without a separate
00175   // overload
00176   IntrusivePtr& operator=(IntrusivePtr intr_ptr) {
00177     std::swap(obj_p, intr_ptr.obj_p);
00178     return *this;
00179   }
00180 
00181  /**
00182   * A version of the assignment operator which enables pointer type
00183   * conversion (assuming the type passed is implicitly type
00184   * convertible to the managed type, such as a derived type).  This
00185   * method does not throw unless the destructor of a managed object
00186   * throws.
00187   * @param intr_ptr The assignee.
00188   * @return The IntrusivePtr object after assignment.
00189   */
00190   template <class U> IntrusivePtr& operator=(const IntrusivePtr<U>& intr_ptr) {
00191     return operator=(IntrusivePtr(intr_ptr));
00192   }
00193 
00194   /**
00195   * A version of the operator for move assignment which enables
00196   * pointer type conversion (assuming the type passed is implicitly
00197   * type convertible to the managed type, such as a derived type).
00198   * This method does not throw unless the destructor of a managed
00199   * object throws.
00200   * @param intr_ptr The intrusive pointer to be moved.
00201   * @return The IntrusivePtr object after the move operation.
00202   */
00203   template <class U> IntrusivePtr& operator=(IntrusivePtr<U>&& intr_ptr) {
00204     return operator=(IntrusivePtr(std::move(intr_ptr)));
00205   }
00206 
00207 /**
00208   * This method does not throw.
00209   * @return A pointer to the managed object (or NULL if none is
00210   * handled).
00211   */
00212   T* get() const {return obj_p;}
00213 
00214  /**
00215   * This method does not throw.
00216   * @return A reference to the managed object.
00217   */
00218   T& operator*() const {return *obj_p;}
00219 
00220  /**
00221   * This method does not throw.
00222   * @return A pointer to the managed object (or NULL if none is
00223   * handled).
00224   */
00225   T* operator->() const {return obj_p;}
00226 
00227  /**
00228   * Causes the intrusive pointer to cease to manage its managed
00229   * object, deleting it if this is the last intrusive pointer managing
00230   * it.  If the argument passed is not NULL, the intrusive pointer
00231   * will manage the new object passed.  This method does not throw
00232   * unless the destructor of a managed object throws.
00233   * @param ptr NULL (the default), or a new object to manage.
00234   */
00235   void reset(T* ptr = 0) {
00236     IntrusivePtr tmp(ptr);
00237     std::swap(obj_p, tmp.obj_p);
00238   }
00239 
00240  /**
00241   * The destructor does not throw unless the destructor of a managed
00242   * object throws - that should never happen.
00243   */
00244   ~IntrusivePtr() {unreference();}
00245 };
00246 
00247 /**
00248  * @class IntrusiveCounter intrusive_ptr.h c++-gtk-utils/intrusive_ptr.h
00249  * @brief This is a counter class providing the ref() and unref()
00250  * functions required by IntrusivePtr.
00251  * @ingroup handles
00252  * @sa IntrusiveLockCounter.
00253  *
00254  * This is a counter class providing the ref() and unref() functions
00255  * required by IntrusivePtr.  It is intended to be inherited from by
00256  * classes which are to be managed by such a smart pointer.
00257  */
00258 
00259 class IntrusiveCounter {
00260   unsigned int count;
00261 
00262 public:
00263   // we should not be able to copy objects of this class
00264   // - objects, if constructed on the heap, should be passed
00265   // via an IntrusivePtr object.  An object of a derived class
00266   // might still copy itself via its copy constructor and take
00267   // along a new base IntrusiveCounter object constructed via
00268   // the default constructor, and thus have a correct reference
00269   // count of 0, but derived classes should not try to provide
00270   // their own assignment operators.
00271 /**
00272  * This class cannot be copied.  The copy constructor is deleted.
00273  */
00274   IntrusiveCounter(const IntrusiveCounter&) = delete;
00275 /**
00276  * This class cannot be copied.  The assignment operator is deleted.
00277  */
00278   IntrusiveCounter& operator=(const IntrusiveCounter&) = delete;
00279 
00280 /**
00281  * Increments the reference count.  This method does not throw.
00282  */
00283   void ref() {++count;}
00284 
00285 /**
00286  * Decrements the reference count, and if the count reaches 0 deletes
00287  * itself (ie the managed object).  This method does not throw unless
00288  * the destructor of a derived class throws - that should never
00289  * happen.
00290  */
00291   void unref() {
00292     --count;
00293     if (count == 0) delete this;
00294   }
00295 
00296   IntrusiveCounter(): count(0) {}
00297   virtual ~IntrusiveCounter() {}
00298 };
00299 
00300 /**
00301  * @class IntrusiveLockCounter intrusive_ptr.h c++-gtk-utils/intrusive_ptr.h
00302  * @brief This is a counter class providing the ref() and unref()
00303  * functions required by IntrusivePtr, with a thread safe reference
00304  * count..
00305  * @ingroup handles
00306  * @sa IntrusiveCounter.
00307  *
00308  * This is a counter class providing the ref() and unref() functions
00309  * required by IntrusivePtr.  It is intended to be inherited from by
00310  * classes which are to be managed by such a smart pointer, and
00311  * includes locking so that such an inheriting class object can be
00312  * accessed by different IntrusivePtr objects in different threads
00313  * (although the word Lock is in the title, by default it uses glib
00314  * atomic functions to access the reference count rather than a mutex,
00315  * so the overhead should be very small).  Note that only the
00316  * reference count is protected, so this is thread safe in the sense
00317  * in which a raw pointer is thread safe.
00318  *
00319  * As mentioned, by default glib atomic functions are used to provide
00320  * thread-safe manipulation of the reference count.  However, a
00321  * library user can define the symbol
00322  * CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX before this file is parsed so
00323  * as to use mutexes instead, which might be useful for some debugging
00324  * purposes.
00325  */
00326 
00327 class IntrusiveLockCounter {
00328 #ifdef CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX
00329   unsigned int count;
00330   Thread::Mutex mutex;
00331 #else
00332   gint count;
00333 #endif
00334 
00335 public:
00336   // we should not be able to copy objects of this class
00337   // - objects, if constructed on the heap, should be passed
00338   // via an IntrusivePtr object.  An object of a derived class
00339   // might still copy itself via its copy constructor and take
00340   // along a new base IntrusiveLockCounter object constructed via
00341   // the default constructor, and thus have a correct reference
00342   // count of 0, but derived classes should not try to provide
00343   // their own assignment operators.
00344 /**
00345  * This class cannot be copied.  The copy constructor is deleted.
00346  */
00347   IntrusiveLockCounter(const IntrusiveLockCounter&) = delete;
00348 /**
00349  * This class cannot be copied.  The assignment operator is deleted.
00350  */
00351   IntrusiveLockCounter& operator=(const IntrusiveLockCounter&) = delete;
00352 
00353 /**
00354  * Increments the reference count.  This method does not throw.
00355  */
00356   void ref() {
00357 #ifdef CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX
00358     Thread::Mutex::Lock lock(mutex);    
00359     ++count;
00360 #else
00361     g_atomic_int_inc(&count);
00362 #endif
00363   }
00364 
00365 /**
00366  * Decrements the reference count, and if the count reaches 0 deletes
00367  * itself (ie the managed object).  This method does not throw unless
00368  * the destructor of a derived class throws - that should never
00369  * happen.
00370  */
00371   void unref() {
00372 #ifdef CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX
00373     mutex.lock();    
00374     --count;
00375     if (count == 0) {
00376       mutex.unlock();
00377       delete this;
00378     }
00379     else mutex.unlock();
00380 #else
00381     if (g_atomic_int_dec_and_test(&count)) {
00382       delete this;
00383     }
00384 #endif
00385   }
00386 
00387 /**
00388  * By default, glib atomic functions are used to provide thread-safe
00389  * manipulation of the reference count.  However, from version 1.2.0 a
00390  * library user can define the symbol
00391  * CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX before this file is parsed so
00392  * as to use mutexes instead, which might be useful for some debugging
00393  * purposes.  Were she to do so, Cgu::Thread::MutexError might be
00394  * thrown by this constructor if initialization of the mutex fails,
00395  * but it is usually not worth checking for this.
00396  *
00397  * Otherwise, this constructor does not throw.
00398  */
00399   IntrusiveLockCounter(): count(0) {}
00400 
00401 /**
00402  * This destructor does not throw, unless the destructor of a derived
00403  * class throws.
00404  */
00405   virtual ~IntrusiveLockCounter() {}
00406 };
00407 
00408 #if defined(CGU_USE_SMART_PTR_COMPARISON) || defined(DOXYGEN_PARSING)
00409 
00410 // we can use built-in operator == when comparing pointers referencing
00411 // different objects of the same type
00412 /**
00413  * @ingroup handles
00414  *
00415  * This comparison operator does not throw.  It compares the addresses
00416  * of the managed objects.
00417  *
00418  * Since 2.0.0-rc2
00419  */
00420 template <class T>
00421 bool operator==(const IntrusivePtr<T>& s1, const IntrusivePtr<T>& s2) {
00422   return (s1.get() == s2.get());
00423 }
00424 
00425 /**
00426  * @ingroup handles
00427  *
00428  * This comparison operator does not throw.  It compares the addresses
00429  * of the managed objects.
00430  *
00431  * Since 2.0.0-rc2
00432  */
00433 template <class T>
00434 bool operator!=(const IntrusivePtr<T>& s1, const IntrusivePtr<T>& s2) {
00435   return !(s1 == s2);
00436 }
00437 
00438 // we must use std::less rather than the < built-in operator for
00439 // pointers to objects not within the same array or object: "For
00440 // templates greater, less, greater_equal, and less_equal, the
00441 // specializations for any pointer type yield a total order, even if
00442 // the built-in operators <, >, <=, >= do not." (para 20.3.3/8).
00443 /**
00444  * @ingroup handles
00445  *
00446  * This comparison operator does not throw.  It compares the addresses
00447  * of the managed objects.
00448  *
00449  * Since 2.0.0-rc2
00450  */
00451 template <class T>
00452 bool operator<(const IntrusivePtr<T>& s1, const IntrusivePtr<T>& s2) {
00453   return std::less<T*>()(s1.get(), s2.get());
00454 }
00455 
00456 #endif // CGU_USE_SMART_PTR_COMPARISON
00457 
00458 } // namespace Cgu
00459 
00460 // doxygen produces long filenames that tar can't handle:
00461 // we have generic documentation for std::hash specialisations
00462 // in doxygen.main.in
00463 #if defined(CGU_USE_SMART_PTR_COMPARISON) && !defined(DOXYGEN_PARSING)
00464 /* This struct allows InstrusivePtr objects to be keys in unordered
00465    associative containers */
00466 namespace std {
00467 template <class T>
00468 struct hash<Cgu::IntrusivePtr<T>> {
00469   typedef std::size_t result_type;
00470   typedef Cgu::IntrusivePtr<T> argument_type;
00471   result_type operator()(const argument_type& s) const {
00472     // this is fine: std::hash structs do not normally contain data and
00473     // std::hash<T*> certainly won't, so we don't have overhead constructing
00474     // std::hash<T*> on the fly
00475     return std::hash<T*>()(s.get());
00476   }
00477 };
00478 } // namespace std
00479 #endif // CGU_USE_SMART_PTR_COMPARISON
00480 
00481 #endif