c++-gtk-utils
shared_ptr.h
Go to the documentation of this file.
00001 /* Copyright (C) 2004 to 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_SHARED_PTR_H
00040 #define CGU_SHARED_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 // SharedLockPtr class (however, if wanted, this is best left for
00045 // definition in the user code)
00046 /* #define CGU_SHARED_LOCK_PTR_USE_MUTEX 1 */
00047 
00048 #include <utility>    // for std::move and std::swap
00049 #include <exception>
00050 #include <new>
00051 #include <functional> // for std::less and std::hash<T*>
00052 #include <cstddef>    // for std::size_t
00053 
00054 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
00055 #include <c++-gtk-utils/mutex.h>
00056 #else
00057 #include <glib.h>
00058 #endif
00059 
00060 #include <c++-gtk-utils/cgu_config.h>
00061 
00062 /**
00063  * @addtogroup handles handles and smart pointers
00064  */
00065 
00066 namespace Cgu {
00067 
00068 /**
00069  * @class SharedPtrError shared_ptr.h c++-gtk-utils/shared_ptr.h
00070  * @brief This is an exception struct thrown as an alternative to
00071  * deleting a managed object when internal memory allocation for
00072  * SharedPtr or SharedLockPtr fails in their reset() method or in
00073  * their constructor which takes a pointer.
00074  * @ingroup handles
00075  * @sa SharedPtr SharedLockPtr SharedPtrAllocFail
00076  *
00077  * This is an exception struct thrown as an alternative to deleting a
00078  * managed object when SharedPtr<T>::SharedPtr(T*),
00079  * SharedLockPtr<T>::SharedLockPtr(T*), SharedPtr<T>::reset(T*) or
00080  * SharedLockPtr<T>::reset(T*), would otherwise throw std::bad_alloc.
00081  * To make those methods do that, Cgu::SharedPtrAllocFail::leave is
00082  * passed as their second argument.
00083  *
00084  * If the exception is thrown, the struct has a member 'obj' of type
00085  * T*, which is a pointer to the object originally passed to those
00086  * methods, so the user can deal with it appropriately.  This enables
00087  * the result of the new expression to be passed directly as the
00088  * argument to those methods without giving rise to a resource leak,
00089  * as in:
00090  * 
00091  * @code
00092  * using namespace Cgu;
00093  * SharedPtr<T> s;                              // doesn't throw
00094  * try {
00095  *   s.reset(new T, SharedPtrAllocFail::leave); // both T allocation and reset() might throw
00096  * }
00097  * catch (std::bad_alloc&) {
00098  *   ...
00099  * }
00100  * catch (SharedPtrError<T>& e) {
00101  *   e.obj->do_something();
00102  *   ...
00103  * }
00104  * ...
00105  * @endcode 
00106  *
00107  * As above, a catch block will need to deal with std::bad_alloc (if
00108  * the call to the new expression when creating the T object fails)
00109  * as well as SharedPtrError (if the call to the new expression in
00110  * the reset() method fails after a valid T object has been
00111  * constructed).
00112  */
00113 
00114 template <class T> struct SharedPtrError: public std::exception {
00115   T* obj;
00116   virtual const char* what() const throw() {return "SharedPtrError\n";}
00117   SharedPtrError(T* p): obj(p) {}
00118 };
00119 
00120 /**
00121  * enum Cgu::SharedPtrAllocFail::Leave
00122  * The enumerator Cgu::SharedPtrAllocFail::leave is passed as the
00123  * second argument of the reset() method of SharedPtr or
00124  * SharedLockPtr, or in their constructor which takes a pointer, in
00125  * order to prevent the method deleting the object passed to it if
00126  * reset() fails internally because of memory exhaustion.
00127  * @ingroup handles
00128  */
00129 namespace SharedPtrAllocFail {
00130  enum Leave {leave};
00131 }
00132 
00133 
00134 /**
00135  * @class SharedPtr shared_ptr.h c++-gtk-utils/shared_ptr.h
00136  * @brief This is a smart pointer for managing the lifetime of objects
00137  * allocated on freestore.
00138  * @ingroup handles
00139  * @sa SharedLockPtr SharedPtrError
00140  *
00141  * This is a smart pointer for managing the lifetime of objects
00142  * allocated on freestore with the new expression.  A managed object
00143  * will be deleted when the last SharedPtr referencing it is
00144  * destroyed.
00145  *
00146  * @b Comparison @b with @b std::shared_ptr
00147  *
00148  * Most of the things that can be done by this class can be done by
00149  * using std::shared_ptr in C++11, but this class is retained in the
00150  * c++-gtk-utils library not only to retain compatibility with series
00151  * 1.2 of the library, but also to cater for some cases not met (or
00152  * not so easily met) by std::shared_ptr:
00153  *
00154  * (i) Glib memory slices provide an efficient small object allocator
00155  * (they are likely to be significantly more efficient than global
00156  * operator new()/new[](), which generally hands off to malloc(), and
00157  * whilst malloc() is good for large block allocations it is generally
00158  * poor as a small object allocator).  Internal Cgu::SharedPtr
00159  * allocation using glib memory slices can be achieved simply by
00160  * compiling the library with the --with-glib-memory-slices-no-compat
00161  * configuration option.  To use glib memory slices for internal
00162  * allocation within std::shared_ptr, a custom allocator object would
00163  * need to be passed to the shared_ptr constructor on every occasion a
00164  * shared_ptr is constructed to manage a new object (and it cannot be
00165  * templated as a typedef for convenient construction).
00166  *
00167  * (ii) If glib memory slices are not used (which do not throw),
00168  * constructing a shared pointer for a new managed object (or calling
00169  * reset() for a new managed object) might throw if internal
00170  * allocation fails.  Although by default the Cgu::SharedPtr
00171  * implementation will delete the new managed object in such a case,
00172  * it also provides an alternative constructor and reset() method
00173  * which instead enables the new object to be accessed via the thrown
00174  * exception object so that user code can decide what to do;
00175  * std::shared_ptr deletes the new object in every case.
00176  *
00177  * (iii) A user can explicitly state whether the shared pointer object
00178  * is to have atomic increment and decrement-and-test with respect to
00179  * the reference count so that the reference count is thread safe
00180  * ('no' in the case of Cgu::SharedPtr, and 'yes' in the case of
00181  * Cgu::SharedLockPtr).  Using atomic functions is unnecessary if the
00182  * managed object concerned is only addressed in one thread (and might
00183  * cause unwanted cache flushing in certain circumstances).
00184  * std::shared_ptr will generally always use atomic functions with
00185  * respect to its reference count in a multi-threaded program.
00186  *
00187  * In favour of std::shared_ptr, it has an associated std::weak_ptr
00188  * class, which Cgu::SharedPtr does not (there is a
00189  * Cgu::GobjWeakHandle class, but that is cognate with Cgu::GobjHandle
00190  * and is only usable with GObjects).
00191  */
00192 
00193 template <class T> class SharedPtr {
00194 
00195 #ifndef DOXYGEN_PARSING
00196   struct RefItems {
00197     unsigned int* ref_count_p;
00198     T* obj_p;
00199   } ref_items;
00200 #endif
00201 
00202   void unreference() {
00203     if (!ref_items.ref_count_p) return;
00204     --(*ref_items.ref_count_p);
00205     if (*ref_items.ref_count_p == 0) {
00206 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
00207       g_slice_free(unsigned int, ref_items.ref_count_p);
00208 #else
00209       delete ref_items.ref_count_p;
00210 #endif
00211       delete ref_items.obj_p;
00212     }
00213   }
00214 
00215   void reference() {
00216     if (!ref_items.ref_count_p) return;
00217     ++(*ref_items.ref_count_p);
00218   }
00219 
00220 public:
00221 /**
00222  * Constructor taking an unmanaged object.
00223  * @param ptr The object which the SharedPtr is to manage (if any).
00224  * @exception std::bad_alloc This constructor will not throw if the
00225  * 'ptr' argument has a NULL value (the default), otherwise it might
00226  * throw std::bad_alloc if memory is exhausted and the system throws
00227  * in that case.  If such an exception is thrown, this constructor is
00228  * exception safe (it does not leak resources), but as well as
00229  * cleaning itself up this constructor will also delete the managed
00230  * object passed to it to avoid a memory leak.  If such automatic
00231  * deletion is not wanted in that case, use the version of this
00232  * constructor taking a Cgu::SharedPtrAllocFail::Leave tag argument.
00233  * @note std::bad_alloc will not be thrown if the library has been
00234  * installed using the --with-glib-memory-slices-no-compat
00235  * configuration option: instead glib will terminate the program if it
00236  * is unable to obtain memory from the operating system.
00237  */
00238   explicit SharedPtr(T* ptr = 0) {
00239 
00240     if ((ref_items.obj_p = ptr)) { // not NULL
00241 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
00242       ref_items.ref_count_p = g_slice_new(unsigned int);
00243       *ref_items.ref_count_p = 1;
00244 #else
00245       try {
00246         ref_items.ref_count_p = new unsigned int(1);
00247       }
00248       catch (...) {
00249         delete ptr;  // if allocating the int referenced by ref_items.ref_count_p
00250                      // has failed then delete the object to be referenced to
00251                      // avoid a memory leak
00252         throw;
00253       }
00254 #endif
00255     }
00256     else ref_items.ref_count_p = 0;
00257   }
00258 
00259 /**
00260  * Constructor taking an unmanaged object.
00261  * @param ptr The object which the SharedPtr is to manage.
00262  * @param tag Passing the tag emumerator
00263  * Cgu::SharedPtrAllocFail::leave causes this constructor not to
00264  * delete the new managed object passed as the 'ptr' argument in the
00265  * event of internal allocation in this method failing because of
00266  * memory exhaustion (in that event, Cgu::SharedPtrError will be
00267  * thrown).
00268  * @exception Cgu::SharedPtrError This constructor might throw
00269  * Cgu::SharedPtrError if memory is exhausted and the system would
00270  * otherwise throw std::bad_alloc in that case.  This constructor is
00271  * exception safe (it does not leak resources), and if such an
00272  * exception is thrown it will clean itself up, but it will not
00273  * attempt to delete the new managed object passed to it.  Access to
00274  * the object passed to the 'ptr' argument can be obtained via the
00275  * thrown Cgu::SharedPtrError object.
00276  * @note 1. On systems with over-commit/lazy-commit combined with
00277  * virtual memory (swap), it is rarely useful to check for memory
00278  * exhaustion, so in those cases this version of the constructor will
00279  * not be useful.
00280  * @note 2. If the library has been installed using the
00281  * --with-glib-memory-slices-no-compat configuration option this
00282  * version of the constructor will also not be useful: instead glib
00283  * will terminate the program if it is unable to obtain memory from
00284  * the operating system.
00285  */
00286   SharedPtr(T* ptr, Cgu::SharedPtrAllocFail::Leave tag) {
00287 
00288     if ((ref_items.obj_p = ptr)) { // not NULL
00289 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
00290       ref_items.ref_count_p = g_slice_new(unsigned int);
00291       *ref_items.ref_count_p = 1;
00292 #else
00293       try {
00294         ref_items.ref_count_p = new unsigned int(1);
00295       }
00296       catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly
00297         throw SharedPtrError<T>(ptr);
00298       }
00299 #endif
00300     }
00301     else ref_items.ref_count_p = 0;
00302   }
00303 
00304 /**
00305  * Causes the SharedPtr to cease to manage its managed object (if
00306  * any), deleting it if this is the last SharedPtr object managing it.
00307  * If the argument passed is not NULL, the SharedPtr object will
00308  * manage the new object passed (which must not be managed by any
00309  * other SharedPtr object).  This method is exception safe, but see
00310  * the comments below on std::bad_alloc.
00311  * @param ptr NULL (the default), or a new unmanaged object to manage.
00312  * @exception std::bad_alloc This method will not throw if the 'ptr'
00313  * argument has a NULL value (the default) and the destructor of a
00314  * managed object does not throw, otherwise it might throw
00315  * std::bad_alloc if memory is exhausted and the system throws in that
00316  * case.  Note that if such an exception is thrown then this method
00317  * will do nothing (it is strongly exception safe and will continue to
00318  * manage the object it was managing prior to the call), except that
00319  * it will delete the new managed object passed to it to avoid a
00320  * memory leak.  If such automatic deletion in the event of such an
00321  * exception is not wanted, use the reset() method taking a
00322  * Cgu::SharedPtrAllocFail::Leave tag type as its second argument.
00323  * @note std::bad_alloc will not be thrown if the library has been
00324  * installed using the --with-glib-memory-slices-no-compat
00325  * configuration option: instead glib will terminate the program if it
00326  * is unable to obtain memory from the operating system.
00327  */
00328   void reset(T* ptr = 0) {
00329     SharedPtr tmp(ptr);
00330     std::swap(ref_items, tmp.ref_items);
00331   }
00332 
00333 /**
00334  * Causes the SharedPtr to cease to manage its managed object (if
00335  * any), deleting it if this is the last SharedPtr object managing it.
00336  * The SharedPtr object will manage the new object passed (which must
00337  * not be managed by any other SharedPtr object).  This method is
00338  * exception safe, but see the comments below on Cgu::SharedPtrError.
00339  * @param ptr A new unmanaged object to manage (if no new object is to
00340  * be managed, use the version of reset() taking a default value of
00341  * NULL).
00342  * @param tag Passing the tag emumerator
00343  * Cgu::SharedPtrAllocFail::leave causes this method not to delete the
00344  * new managed object passed as the 'ptr' argument in the event of
00345  * internal allocation in this method failing because of memory
00346  * exhaustion (in that event, Cgu::SharedPtrError will be thrown).
00347  * @exception Cgu::SharedPtrError This method might throw
00348  * Cgu::SharedPtrError if memory is exhausted and the system would
00349  * otherwise throw std::bad_alloc in that case.  Note that if such an
00350  * exception is thrown then this method will do nothing (it is
00351  * strongly exception safe and will continue to manage the object it
00352  * was managing prior to the call), and it will not attempt to delete
00353  * the new managed object passed to it.  Access to the object passed
00354  * to the 'ptr' argument can be obtained via the thrown
00355  * Cgu::SharedPtrError object.
00356  * @note 1. On systems with over-commit/lazy-commit combined with
00357  * virtual memory (swap), it is rarely useful to check for memory
00358  * exhaustion, so in those cases this version of the reset() method
00359  * will not be useful.
00360  * @note 2. If the library has been installed using the
00361  * --with-glib-memory-slices-no-compat configuration option this
00362  * version of the reset() method will also not be useful: instead glib
00363  * will terminate the program if it is unable to obtain memory from
00364  * the operating system.
00365  */
00366   void reset(T* ptr, Cgu::SharedPtrAllocFail::Leave tag) {
00367     SharedPtr tmp(ptr, tag);
00368     std::swap(ref_items, tmp.ref_items);
00369   }
00370 
00371  /**
00372   * This copy constructor does not throw.
00373   * @param sh_ptr The shared pointer to be copied.
00374   */
00375   SharedPtr(const SharedPtr& sh_ptr) {
00376     ref_items = sh_ptr.ref_items;
00377     reference();
00378   }
00379 
00380  /**
00381   * The move constructor does not throw.  It has move semantics.
00382   * @param sh_ptr The shared pointer to be moved.
00383   */
00384   SharedPtr(SharedPtr&& sh_ptr) {
00385     ref_items = sh_ptr.ref_items;
00386     sh_ptr.ref_items.ref_count_p = 0;
00387     sh_ptr.ref_items.obj_p = 0;
00388   }
00389 
00390   template <class U> friend class SharedPtr;
00391 
00392  /**
00393   * A version of the copy constructor which enables pointer type
00394   * conversion (assuming the type passed is implicitly type
00395   * convertible to the managed type, such as a derived type).  This
00396   * copy constructor does not throw.
00397   * @param sh_ptr The shared pointer to be copied.
00398   */
00399   template <class U> SharedPtr(const SharedPtr<U>& sh_ptr) {
00400     // because we are allowing an implicit cast from derived to
00401     // base class referenced object, we need to assign from each
00402     // member of sh_ptr.ref_items separately
00403     ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p;
00404     ref_items.obj_p = sh_ptr.ref_items.obj_p;
00405     reference();
00406   }
00407 
00408  /**
00409   * A version of the move constructor which enables pointer type
00410   * conversion (assuming the type passed is implicitly type
00411   * convertible to the managed type, such as a derived type).  This
00412   * move constructor does not throw.
00413   * @param sh_ptr The shared pointer to be moved.
00414   */
00415   template <class U> SharedPtr(SharedPtr<U>&& sh_ptr) {
00416     // because we are allowing an implicit cast from derived to
00417     // base class referenced object, we need to assign from each
00418     // member of sh_ptr.ref_items separately
00419     ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p;
00420     ref_items.obj_p = sh_ptr.ref_items.obj_p;
00421     sh_ptr.ref_items.ref_count_p = 0;
00422     sh_ptr.ref_items.obj_p = 0;
00423   }
00424 
00425  /**
00426   * This method (and so copy or move assignment) does not throw unless
00427   * the destructor of a managed object throws.
00428   * @param sh_ptr the assignor.
00429   * @return The SharedPtr object after assignment.
00430   */
00431   // having a value type as the argument, rather than reference to const
00432   // and then initialising a tmp object, gives the compiler more scope
00433   // for optimisation, and also caters for r-values without a separate
00434   // overload
00435   SharedPtr& operator=(SharedPtr sh_ptr) {
00436     std::swap(ref_items, sh_ptr.ref_items);
00437     return *this;
00438   }
00439 
00440  /**
00441   * A version of the assignment operator which enables pointer type
00442   * conversion (assuming the type passed is implicitly type
00443   * convertible to the managed type, such as a derived type).  This
00444   * method does not throw unless the destructor of a managed object
00445   * throws.
00446   * @param sh_ptr the assignor.
00447   * @return The SharedPtr object after assignment.
00448   */
00449   template <class U> SharedPtr& operator=(const SharedPtr<U>& sh_ptr) {
00450     return operator=(SharedPtr(sh_ptr));
00451   }
00452 
00453  /**
00454   * A version of the operator for move assignment which enables
00455   * pointer type conversion (assuming the type passed is implicitly
00456   * type convertible to the managed type, such as a derived type).
00457   * This method does not throw unless the destructor of a managed
00458   * object throws.
00459   * @param sh_ptr the shared pointer to be moved.
00460   * @return The SharedPtr object after the move operation.
00461   */
00462   template <class U> SharedPtr& operator=(SharedPtr<U>&& sh_ptr) {
00463     return operator=(SharedPtr(std::move(sh_ptr)));
00464   }
00465 
00466  /**
00467   * This method does not throw.
00468   * @return A pointer to the managed object (or NULL if none is
00469   * managed).
00470   */
00471   T* get() const {return ref_items.obj_p;}
00472 
00473  /**
00474   * This method does not throw.
00475   * @return A reference to the managed object.
00476   */
00477   T& operator*() const {return *ref_items.obj_p;}
00478 
00479  /**
00480   * This method does not throw.
00481   * @return A pointer to the managed object  (or NULL if none is
00482   * managed).
00483   */
00484   T* operator->() const {return ref_items.obj_p;}
00485 
00486  /**
00487   * This method does not throw.
00488   * @return The number of SharedPtr objects referencing the managed
00489   * object (or 0 if none is managed by this SharedPtr).
00490   */
00491   unsigned int get_refcount() const {return (ref_items.ref_count_p) ? *ref_items.ref_count_p : 0;}
00492 
00493  /**
00494   * The destructor does not throw unless the destructor of a managed
00495   * object throws - that should never happen.
00496   */
00497   ~SharedPtr() {unreference();}
00498 };
00499 
00500 /**
00501  * @class SharedLockPtr shared_ptr.h c++-gtk-utils/shared_ptr.h
00502  * @brief This is a smart pointer for managing the lifetime of objects
00503  * allocated on freestore, with a thread safe reference count.
00504  * @ingroup handles
00505  * @sa SharedPtr SharedPtrError
00506  *
00507  * Class SharedLockPtr is a version of the shared pointer class which
00508  * includes locking so that it can be accessed in multiple threads
00509  * (although the word Lock is in the title, by default it uses glib
00510  * atomic functions to access the reference count rather than a mutex,
00511  * so the overhead should be very small).  Note that only the
00512  * reference count is protected, so this is thread safe in the sense
00513  * in which a raw pointer is thread safe.  A shared pointer accessed
00514  * in one thread referencing a particular object is thread safe as
00515  * against another shared pointer accessing the same object in a
00516  * different thread.  It is thus suitable for use in different Std C++
00517  * containers which exist in different threads but which contain
00518  * shared objects by reference.  But:
00519  *
00520  * 1.  If the referenced object is to be modified in one thread and
00521  *     read or modified in another thread an appropriate mutex for the
00522  *     referenced object is required (unless that referenced object
00523  *     does its own locking).
00524  *
00525  * 2.  If the same instance of shared pointer is to be modified in one
00526  *     thread (by assigning to the pointer so that it references a
00527  *     different object), and copied (assigned from or used as the
00528  *     argument of a copy constructor) or modified in another thread,
00529  *     a mutex for that instance of shared pointer is required.
00530  *
00531  * 3.  Objects referenced by shared pointers which are objects for
00532  *     which POSIX provides no guarantees (in the main, those which
00533  *     are not built-in types), such as strings and similar
00534  *     containers, may not support concurrent reads in different
00535  *     threads.  That depends on the library implementation concerned.
00536  *     If that is the case, a mutex for the referenced object will
00537  *     also be required when reading any given instance of such an
00538  *     object in more than one thread by dereferencing any shared
00539  *     pointers referencing it (and indeed, when not using shared
00540  *     pointers at all).
00541  *
00542  * As mentioned, by default glib atomic functions are used to provide
00543  * thread-safe manipulation of the reference count.  However, a
00544  * library user can define the symbol CGU_SHARED_LOCK_PTR_USE_MUTEX
00545  * before shared_ptr.h is parsed so as to use mutexes instead, which
00546  * might be useful for some debugging purposes.
00547  *
00548  * @b Comparison @b with @b std::shared_ptr
00549  *
00550  * Most of the things that can be done by this class can be done by
00551  * using std::shared_ptr in C++11, but this class is retained in the
00552  * c++-gtk-utils library not only to retain compatibility with series
00553  * 1.2 of the library, but also to cater for some cases not met (or
00554  * not so easily met) by std::shared_ptr:
00555  *
00556  * (i) Glib memory slices provide an efficient small object allocator
00557  * (they are likely to be significantly more efficient than global
00558  * operator new()/new[](), which generally hands off to malloc(), and
00559  * whilst malloc() is good for large block allocations it is generally
00560  * poor as a small object allocator).  Internal Cgu::SharedLockPtr
00561  * allocation using glib memory slices can be achieved simply by
00562  * compiling the library with the --with-glib-memory-slices-no-compat
00563  * configuration option.  To use glib memory slices for internal
00564  * allocation within std::shared_ptr, a custom allocator object would
00565  * need to be passed to the shared_ptr constructor on every occasion a
00566  * shared_ptr is constructed to manage a new object (and it cannot be
00567  * templated as a typedef for convenient construction).
00568  *
00569  * (ii) If glib memory slices are not used (which do not throw),
00570  * constructing a shared pointer for a new managed object (or calling
00571  * reset() for a new managed object) might throw if internal
00572  * allocation fails.  Although by default the Cgu::SharedLockPtr
00573  * implementation will delete the new managed object in such a case,
00574  * it also provides an alternative constructor and reset() method
00575  * which instead enables the new object to be accessed via the thrown
00576  * exception object so that user code can decide what to do;
00577  * std::shared_ptr deletes the new object in every case.
00578  *
00579  * (iii) A user can explicitly state whether the shared pointer object
00580  * is to have atomic increment and decrement-and-test with respect to
00581  * the reference count so that the reference count is thread safe
00582  * ('no' in the case of Cgu::SharedPtr, and 'yes' in the case of
00583  * Cgu::SharedLockPtr).  Using atomic functions is unnecessary if the
00584  * managed object concerned is only addressed in one thread (and might
00585  * cause unwanted cache flushing in certain circumstances).
00586  * std::shared_ptr will generally always use atomic functions with
00587  * respect to its reference count in a multi-threaded program.
00588  *
00589  * In favour of std::shared_ptr, it has an associated std::weak_ptr
00590  * class, which Cgu::SharedLockPtr does not (there is a
00591  * Cgu::GobjWeakHandle class, but that is cognate with Cgu::GobjHandle
00592  * and is only usable with GObjects).  In addition shared_ptr objects
00593  * have some atomic store, load and exchange functions provided for
00594  * them which enable concurrent modifications of the same instance of
00595  * shared_ptr in different threads to have defined results.
00596  */
00597 
00598 template <class T> class SharedLockPtr {
00599 
00600 #ifndef DOXYGEN_PARSING
00601   struct RefItems {
00602 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
00603     Thread::Mutex* mutex_p;
00604     unsigned int* ref_count_p;
00605 #else
00606     gint* ref_count_p;
00607 #endif
00608     T* obj_p;
00609   } ref_items;
00610 #endif
00611 
00612   // SharedLockPtr<T>::unreference() does not throw if the destructor of the
00613   // contained object does not throw, because  Thread::Mutex::~Mutex(),
00614   // Thread::Mutex::lock() and Thread::Mutex::unlock() do not throw
00615   void unreference() {
00616     // we can (and should) check whether ref_items.ref_count_p is NULL without
00617     // a lock, because that member is specific to this SharedLockPtr object.
00618     // Only the integer pointed to by it is shared amongst SharedLockPtr
00619     // objects and requires locking
00620     if (!ref_items.ref_count_p) return;
00621 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
00622     ref_items.mutex_p->lock();
00623     --(*ref_items.ref_count_p);
00624     if (*ref_items.ref_count_p == 0) {
00625 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
00626       g_slice_free(unsigned int, ref_items.ref_count_p);
00627 # else
00628       delete ref_items.ref_count_p;
00629 # endif
00630       ref_items.mutex_p->unlock();
00631       delete ref_items.mutex_p;
00632       delete ref_items.obj_p;
00633     }
00634     else ref_items.mutex_p->unlock();
00635 #else
00636     if (g_atomic_int_dec_and_test(ref_items.ref_count_p)) {
00637 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
00638       g_slice_free(gint, ref_items.ref_count_p);
00639 # else
00640       delete ref_items.ref_count_p;
00641 # endif
00642       delete ref_items.obj_p;
00643     }
00644 #endif
00645   }
00646 
00647   // SharedLockPtr<T>::reference() does not throw because
00648   // Thread::Mutex::Lock::Lock() and Thread::Mutex::Lock::~Lock() do not throw
00649   void reference() {
00650     // we can (and should) check whether ref_items.ref_count_p is NULL without
00651     // a lock, because that member is specific to this SharedLockPtr object.
00652     // Only the integer pointed to by it is shared amongst SharedLockPtr
00653     // objects and requires locking
00654     if (!ref_items.ref_count_p) return;
00655 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
00656     Thread::Mutex::Lock lock(*ref_items.mutex_p);
00657     ++(*ref_items.ref_count_p);
00658 #else
00659     g_atomic_int_inc(ref_items.ref_count_p);
00660 #endif
00661   }
00662 
00663 public:
00664 /**
00665  * Constructor taking an unmanaged object.
00666  * @param ptr The object which the SharedLockPtr is to manage (if
00667  * any).
00668  * @exception std::bad_alloc This constructor will not throw if the
00669  * 'ptr' argument has a NULL value (the default), otherwise it might
00670  * throw std::bad_alloc if memory is exhausted and the system throws
00671  * in that case.  If such an exception is thrown, this constructor is
00672  * exception safe (it does not leak resources), but as well as
00673  * cleaning itself up this constructor will also delete the managed
00674  * object passed to it to avoid a memory leak.  If such automatic
00675  * deletion is not wanted in that case, use the version of this
00676  * constructor taking a Cgu::SharedPtrAllocFail::Leave tag argument.
00677  * @note 1. std::bad_alloc will not be thrown if the library has been
00678  * installed using the --with-glib-memory-slices-no-compat
00679  * configuration option: instead glib will terminate the program if it
00680  * is unable to obtain memory from the operating system.
00681  * @note 2. By default, glib atomic functions are used to provide
00682  * thread-safe manipulation of the reference count.  However, a
00683  * library user can define the symbol CGU_SHARED_LOCK_PTR_USE_MUTEX
00684  * before shared_ptr.h is parsed so as to use mutexes instead, which
00685  * might be useful for some debugging purposes.  Were she to do so,
00686  * Cgu::Thread::MutexError might be thrown by this constructor if
00687  * initialization of the mutex fails, but it is usually not worth
00688  * checking for this.
00689  */
00690   explicit SharedLockPtr(T* ptr = 0) {
00691 
00692     if ((ref_items.obj_p = ptr)) { // not NULL
00693 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
00694       try {
00695         ref_items.mutex_p = new Thread::Mutex;
00696       }
00697       catch (...) {
00698         delete ptr;  // if allocating the object referenced by ref_items.mutex_p
00699                      // has failed then delete the object to be referenced to
00700                      // avoid a memory leak
00701         throw;
00702       }
00703 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
00704       ref_items.ref_count_p = g_slice_new(unsigned int);
00705       *ref_items.ref_count_p = 1;
00706 # else
00707       try {
00708         ref_items.ref_count_p = new unsigned int(1);
00709       }
00710       catch (...) {
00711         delete ref_items.mutex_p;
00712         delete ptr;
00713         throw;
00714       }
00715 # endif
00716 #else
00717 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
00718       ref_items.ref_count_p = g_slice_new(gint);
00719       *ref_items.ref_count_p = 1;
00720 # else
00721       try {
00722         ref_items.ref_count_p = new gint(1);
00723       }
00724       catch (...) {
00725         delete ptr;  // if allocating the int referenced by ref_items.ref_count_p
00726                      // has failed then delete the object to be referenced to
00727                      // avoid a memory leak
00728         throw;
00729       }
00730 # endif
00731 #endif
00732     }
00733     else {
00734 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
00735       ref_items.mutex_p = 0;  // make sure the value is valid as we may assign it
00736 #endif
00737       ref_items.ref_count_p = 0;
00738     }
00739   }
00740 
00741 /**
00742  * Constructor taking an unmanaged object.
00743  * @param ptr The object which the SharedLockPtr is to manage.
00744  * @param tag Passing the tag emumerator
00745  * Cgu::SharedPtrAllocFail::leave causes this constructor not to
00746  * delete the new managed object passed as the 'ptr' argument in the
00747  * event of internal allocation in this method failing because of
00748  * memory exhaustion (in that event, Cgu::SharedPtrError will be
00749  * thrown).
00750  * @exception Cgu::SharedPtrError This constructor might throw
00751  * Cgu::SharedPtrError if memory is exhausted and the system would
00752  * otherwise throw std::bad_alloc in that case.  This constructor is
00753  * exception safe (it does not leak resources), and if such an
00754  * exception is thrown it will clean itself up, but it will not
00755  * attempt to delete the new managed object passed to it.  Access to
00756  * the object passed to the 'ptr' argument can be obtained via the
00757  * thrown Cgu::SharedPtrError object.
00758  * @note 1. On systems with over-commit/lazy-commit combined with
00759  * virtual memory (swap), it is rarely useful to check for memory
00760  * exhaustion, so in those cases this version of the constructor will
00761  * not be useful.
00762  * @note 2. If the library has been installed using the
00763  * --with-glib-memory-slices-no-compat configuration option this
00764  * version of the constructor will also not be useful: instead glib
00765  * will terminate the program if it is unable to obtain memory from
00766  * the operating system.
00767  * @note 3. By default, glib atomic functions are used to provide
00768  * thread-safe manipulation of the reference count.  However, a
00769  * library user can define the symbol CGU_SHARED_LOCK_PTR_USE_MUTEX
00770  * before shared_ptr.h is parsed so as to use mutexes instead, which
00771  * might be useful for some debugging purposes.  Were she to do so,
00772  * Cgu::SharedPtrError might be thrown by this constructor if
00773  * initialization of the mutex fails (even if the
00774  * --with-glib-memory-slices-no-compat configuration option is
00775  * chosen), but it is usually not worth checking for such mutex
00776  * initialization failure.
00777  */
00778   SharedLockPtr(T* ptr, Cgu::SharedPtrAllocFail::Leave tag) {
00779 
00780     if ((ref_items.obj_p = ptr)) { // not NULL
00781 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
00782       try {
00783         ref_items.mutex_p = new Thread::Mutex;
00784       }
00785       catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly
00786         throw SharedPtrError<T>(ptr);
00787       }
00788       catch (Thread::MutexError&) { // as we are not rethrowing, make NPTL friendly
00789         throw SharedPtrError<T>(ptr);
00790       }
00791 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
00792       ref_items.ref_count_p = g_slice_new(unsigned int);
00793       *ref_items.ref_count_p = 1;
00794 # else
00795       try {
00796         ref_items.ref_count_p = new unsigned int(1);
00797       }
00798       catch (std::bad_alloc&) {
00799         delete ref_items.mutex_p;
00800         throw SharedPtrError<T>(ptr);
00801       }
00802 # endif
00803 #else
00804 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
00805       ref_items.ref_count_p = g_slice_new(gint);
00806       *ref_items.ref_count_p = 1;
00807 # else
00808       try {
00809         ref_items.ref_count_p = new gint(1);
00810       }
00811       catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly
00812         throw SharedPtrError<T>(ptr);
00813       }
00814 # endif
00815 #endif
00816     }
00817     else {
00818 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
00819       ref_items.mutex_p = 0;  // make sure the value is valid as we may assign it
00820 #endif
00821       ref_items.ref_count_p = 0;
00822     }
00823   }
00824 
00825 /**
00826  * Causes the SharedLockPtr to cease to manage its managed object (if
00827  * any), deleting it if this is the last SharedLockPtr object managing
00828  * it.  If the argument passed is not NULL, the SharedLockPtr object
00829  * will manage the new object passed (which must not be managed by any
00830  * other SharedLockPtr object).  This method is exception safe, but
00831  * see the comments below on std::bad_alloc.
00832  * @param ptr NULL (the default), or a new unmanaged object to manage.
00833  * @exception std::bad_alloc This method will not throw if the 'ptr'
00834  * argument has a NULL value (the default) and the destructor of a
00835  * managed object does not throw, otherwise it might throw
00836  * std::bad_alloc if memory is exhausted and the system throws in that
00837  * case.  Note that if such an exception is thrown then this method
00838  * will do nothing (it is strongly exception safe and will continue to
00839  * manage the object it was managing prior to the call), except that
00840  * it will delete the new managed object passed to it to avoid a
00841  * memory leak.  If such automatic deletion in the event of such an
00842  * exception is not wanted, use the reset() method taking a
00843  * Cgu::SharedPtrAllocFail::Leave tag type as its second argument.
00844  * @note 1. std::bad_alloc will not be thrown if the library has been
00845  * installed using the --with-glib-memory-slices-no-compat
00846  * configuration option: instead glib will terminate the program if it
00847  * is unable to obtain memory from the operating system.
00848  * @note 2. By default, glib atomic functions are used to provide
00849  * thread-safe manipulation of the reference count.  However, a
00850  * library user can define the symbol CGU_SHARED_LOCK_PTR_USE_MUTEX
00851  * before shared_ptr.h is parsed so as to use mutexes instead, which
00852  * might be useful for some debugging purposes.  Were she to do so,
00853  * Cgu::Thread::MutexError might be thrown by this method if
00854  * initialization of the mutex fails, but it is usually not worth
00855  * checking for this.
00856  * @note 3. A SharedLockPtr object protects its reference count but
00857  * not the managed object or its other internals.  The reset() method
00858  * should not be called by one thread in respect of a particular
00859  * SharedLockPtr object while another thread may be operating on,
00860  * copying or dereferencing the same instance of SharedLockPtr.  It is
00861  * thread-safe as against another instance of SharedLockPtr managing
00862  * the same object.
00863  */
00864   void reset(T* ptr = 0) {
00865     SharedLockPtr tmp(ptr);
00866     std::swap(ref_items, tmp.ref_items);
00867   }
00868 
00869 /**
00870  * Causes the SharedLockPtr to cease to manage its managed object (if
00871  * any), deleting it if this is the last SharedLockPtr object managing
00872  * it.  The SharedLockPtr object will manage the new object passed
00873  * (which must not be managed by any other SharedLockPtr object).
00874  * This method is exception safe, but see the comments below on
00875  * Cgu::SharedPtrError.
00876  * @param ptr A new unmanaged object to manage (if no new object is to
00877  * be managed, use the version of reset() taking a default value of
00878  * NULL).
00879  * @param tag Passing the tag emumerator
00880  * Cgu::SharedPtrAllocFail::leave causes this method not to delete the
00881  * new managed object passed as the 'ptr' argument in the event of
00882  * internal allocation in this method failing because of memory
00883  * exhaustion (in that event, Cgu::SharedPtrError will be thrown).
00884  * @exception Cgu::SharedPtrError This method might throw
00885  * Cgu::SharedPtrError if memory is exhausted and the system would
00886  * otherwise throw std::bad_alloc in that case.  Note that if such an
00887  * exception is thrown then this method will do nothing (it is
00888  * strongly exception safe and will continue to manage the object it
00889  * was managing prior to the call), and it will not attempt to delete
00890  * the new managed object passed to it.  Access to the object passed
00891  * to the 'ptr' argument can be obtained via the thrown
00892  * Cgu::SharedPtrError object.
00893  * @note 1. A SharedLockPtr object protects its reference count but
00894  * not the managed object or its other internals.  The reset() method
00895  * should not be called by one thread in respect of a particular
00896  * SharedLockPtr object while another thread may be operating on,
00897  * copying or dereferencing the same instance of SharedLockPtr.  It is
00898  * thread-safe as against another instance of SharedLockPtr managing
00899  * the same object.
00900  * @note 2. On systems with over-commit/lazy-commit combined with
00901  * virtual memory (swap), it is rarely useful to check for memory
00902  * exhaustion, so in those cases this version of the reset() method
00903  * will not be useful.
00904  * @note 3. If the library has been installed using the
00905  * --with-glib-memory-slices-no-compat configuration option this
00906  * version of the reset() method will also not be useful: instead glib
00907  * will terminate the program if it is unable to obtain memory from
00908  * the operating system.
00909  * @note 4. By default, glib atomic functions are used to provide
00910  * thread-safe manipulation of the reference count.  However, a
00911  * library user can define the symbol CGU_SHARED_LOCK_PTR_USE_MUTEX
00912  * before shared_ptr.h is parsed so as to use mutexes instead, which
00913  * might be useful for some debugging purposes.  Were she to do so,
00914  * Cgu::SharedPtrError might be thrown by this method if
00915  * initialization of the mutex fails (even if the
00916  * --with-glib-memory-slices-no-compat configuration option is
00917  * chosen), but it is usually not worth checking for such mutex
00918  * initialization failure.
00919  */
00920   void reset(T* ptr, Cgu::SharedPtrAllocFail::Leave tag) {
00921     SharedLockPtr tmp(ptr, tag);
00922     std::swap(ref_items, tmp.ref_items);
00923   }
00924 
00925  /**
00926   * This copy constructor does not throw.
00927   * @param sh_ptr The shared pointer to be copied.
00928   */
00929   SharedLockPtr(const SharedLockPtr& sh_ptr) {
00930     ref_items = sh_ptr.ref_items;
00931     reference();
00932   }
00933 
00934  /**
00935   * The move constructor does not throw.  It has move semantics.
00936   * @param sh_ptr The shared pointer to be moved.
00937   */
00938   SharedLockPtr(SharedLockPtr&& sh_ptr) {
00939     ref_items = sh_ptr.ref_items;
00940 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
00941     sh_ptr.ref_items.mutex_p = 0;  // make sure the value is valid as we may assign it
00942 #endif
00943     sh_ptr.ref_items.ref_count_p = 0;
00944     sh_ptr.ref_items.obj_p = 0;
00945   }
00946 
00947   template <class U> friend class SharedLockPtr;
00948 
00949  /**
00950   * A version of the copy constructor which enables pointer type
00951   * conversion (assuming the type passed is implicitly type
00952   * convertible to the managed type, such as a derived type).  This
00953   * copy constructor does not throw.
00954   * @param sh_ptr The shared pointer to be copied.
00955   */
00956   template <class U> SharedLockPtr(const SharedLockPtr<U>& sh_ptr) {
00957     // because we are allowing an implicit cast from derived to
00958     // base class referenced object, we need to assign from each
00959     // member of sh_ptr.ref_items separately
00960 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
00961     ref_items.mutex_p = sh_ptr.ref_items.mutex_p;
00962 #endif
00963     ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p;
00964     ref_items.obj_p = sh_ptr.ref_items.obj_p;
00965     reference();
00966   }
00967 
00968  /**
00969   * A version of the move constructor which enables pointer type
00970   * conversion (assuming the type passed is implicitly type
00971   * convertible to the managed type, such as a derived type).  This
00972   * move constructor does not throw.
00973   * @param sh_ptr The shared pointer to be moved.
00974   */
00975   template <class U> SharedLockPtr(SharedLockPtr<U>&& sh_ptr) {
00976     // because we are allowing an implicit cast from derived to
00977     // base class referenced object, we need to assign from each
00978     // member of sh_ptr.ref_items separately
00979 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
00980     ref_items.mutex_p = sh_ptr.ref_items.mutex_p;
00981 #endif
00982     ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p;
00983     ref_items.obj_p = sh_ptr.ref_items.obj_p;
00984 
00985 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
00986     sh_ptr.ref_items.mutex_p = 0;  // make sure the value is valid as we may assign it
00987 #endif
00988     sh_ptr.ref_items.ref_count_p = 0;
00989     sh_ptr.ref_items.obj_p = 0;
00990   }
00991 
00992  /**
00993   * This method (and so copy or move assignment) does not throw unless
00994   * the destructor of a managed object throws.
00995   * @param sh_ptr the assignor.
00996   * @return The SharedLockPtr object after assignment.
00997   */
00998   // having a value type as the argument, rather than reference to const
00999   // and then initialising a tmp object, gives the compiler more scope
01000   // for optimisation, and also caters for r-values without a separate
01001   // overload
01002   SharedLockPtr& operator=(SharedLockPtr sh_ptr) {
01003     std::swap(ref_items, sh_ptr.ref_items);
01004     return *this;
01005   }
01006 
01007  /**
01008   * A version of the assignment operator which enables pointer type
01009   * conversion (assuming the type passed is implicitly type
01010   * convertible to the managed type, such as a derived type).  This
01011   * method does not throw unless the destructor of a managed object
01012   * throws.
01013   * @param sh_ptr the assignor.
01014   * @return The SharedLockPtr object after assignment.
01015   */
01016   template <class U> SharedLockPtr& operator=(const SharedLockPtr<U>& sh_ptr) {
01017     return operator=(SharedLockPtr(sh_ptr));
01018   }
01019   
01020  /**
01021   * A version of the operator for move assignment which enables
01022   * pointer type conversion (assuming the type passed is implicitly
01023   * type convertible to the managed type, such as a derived type).
01024   * This method does not throw unless the destructor of a managed
01025   * object throws.
01026   * @param sh_ptr the shared pointer to be moved.
01027   * @return The SharedLockPtr object after the move operation.
01028   */
01029   template <class U> SharedLockPtr& operator=(SharedLockPtr<U>&& sh_ptr) {
01030     return operator=(SharedLockPtr(std::move(sh_ptr)));
01031   }
01032 
01033  /**
01034   * This method does not throw.
01035   * @return A pointer to the managed object (or NULL if none is
01036   * managed).
01037   */
01038   T* get() const {return ref_items.obj_p;}
01039 
01040  /**
01041   * This method does not throw.
01042   * @return A reference to the managed object.
01043   */
01044   T& operator*() const {return *ref_items.obj_p;}
01045 
01046  /**
01047   * This method does not throw.
01048   * @return A pointer to the managed object (or NULL if none is
01049   * managed).
01050   */
01051   T* operator->() const {return ref_items.obj_p;}
01052 
01053  /**
01054   * This method does not throw.
01055   * @return The number of SharedLockPtr objects referencing the
01056   * managed object (or 0 if none is managed by this SharedLockPtr).
01057   * @note The return value may not be valid if another thread has
01058   * changed the reference count before the value returned by this
01059   * method is acted on.  It is provided as a utility, but may not be
01060   * meaningful, depending on the intended usage.
01061   */
01062   unsigned int get_refcount() const {
01063     if (!ref_items.ref_count_p) return 0;
01064 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
01065     Thread::Mutex::Lock lock(*ref_items.mutex_p);
01066     return *ref_items.ref_count_p;
01067 #else
01068     return g_atomic_int_get(ref_items.ref_count_p);
01069 #endif
01070   }
01071 
01072  /**
01073   * The destructor does not throw unless the destructor of a managed
01074   * object throws - that should never happen.
01075   */
01076   ~SharedLockPtr() {unreference();}
01077 };
01078 
01079 #if defined(CGU_USE_SMART_PTR_COMPARISON) || defined(DOXYGEN_PARSING)
01080 
01081 // we can use built-in operator == when comparing pointers referencing
01082 // different objects of the same type
01083 /**
01084  * @ingroup handles
01085  *
01086  * This comparison operator does not throw.  It compares the addresses
01087  * of the managed objects.
01088  *
01089  * Since 2.0.0-rc2
01090  */
01091 template <class T>
01092 bool operator==(const SharedPtr<T>& s1, const SharedPtr<T>& s2) {
01093   return (s1.get() == s2.get());
01094 }
01095 
01096 /**
01097  * @ingroup handles
01098  *
01099  * This comparison operator does not throw.  It compares the addresses
01100  * of the managed objects.
01101  *
01102  * Since 2.0.0-rc2
01103  */
01104 template <class T>
01105 bool operator!=(const SharedPtr<T>& s1, const SharedPtr<T>& s2) {
01106   return !(s1 == s2);
01107 }
01108 
01109 // we must use std::less rather than the < built-in operator for
01110 // pointers to objects not within the same array or object: "For
01111 // templates greater, less, greater_equal, and less_equal, the
01112 // specializations for any pointer type yield a total order, even if
01113 // the built-in operators <, >, <=, >= do not." (para 20.3.3/8).
01114 /**
01115  * @ingroup handles
01116  *
01117  * This comparison operator does not throw.  It compares the addresses
01118  * of the managed objects.
01119  *
01120  * Since 2.0.0-rc2
01121  */
01122 template <class T>
01123 bool operator<(const SharedPtr<T>& s1, const SharedPtr<T>& s2) {
01124   return std::less<T*>()(s1.get(), s2.get());
01125 }
01126 
01127 /**
01128  * @ingroup handles
01129  *
01130  * This comparison operator does not throw.  It compares the addresses
01131  * of the managed objects.
01132  *
01133  * Since 2.0.0-rc2
01134  */
01135 template <class T>
01136 bool operator==(const SharedLockPtr<T>& s1, const SharedLockPtr<T>& s2) {
01137   return (s1.get() == s2.get());
01138 }
01139 
01140 /**
01141  * @ingroup handles
01142  *
01143  * This comparison operator does not throw.  It compares the addresses
01144  * of the managed objects.
01145  *
01146  * Since 2.0.0-rc2
01147  */
01148 template <class T>
01149 bool operator!=(const SharedLockPtr<T>& s1, const SharedLockPtr<T>& s2) {
01150   return !(s1 == s2);
01151 }
01152 
01153 /**
01154  * @ingroup handles
01155  *
01156  * This comparison operator does not throw.  It compares the addresses
01157  * of the managed objects.
01158  *
01159  * Since 2.0.0-rc2
01160  */
01161 template <class T>
01162 bool operator<(const SharedLockPtr<T>& s1, const SharedLockPtr<T>& s2) {
01163   return std::less<T*>()(s1.get(), s2.get());
01164 }
01165 
01166 #endif // CGU_USE_SMART_PTR_COMPARISON
01167 
01168 } // namespace Cgu
01169 
01170 // doxygen produces long filenames that tar can't handle:
01171 // we have generic documentation for std::hash specialisations
01172 // in doxygen.main.in
01173 #if defined(CGU_USE_SMART_PTR_COMPARISON) && !defined(DOXYGEN_PARSING)
01174 /* These structs allow SharedPtr and SharedLockPtr objects to be keys
01175    in unordered associative containers */
01176 namespace std {
01177 template <class T>
01178 struct hash<Cgu::SharedPtr<T>> {
01179   typedef std::size_t result_type;
01180   typedef Cgu::SharedPtr<T> argument_type;
01181   result_type operator()(const argument_type& s) const {
01182     // this is fine: std::hash structs do not normally contain data and
01183     // std::hash<T*> certainly won't, so we don't have overhead constructing
01184     // std::hash<T*> on the fly
01185     return std::hash<T*>()(s.get());
01186   }
01187 };
01188 template <class T>
01189 struct hash<Cgu::SharedLockPtr<T>> {
01190   typedef std::size_t result_type;
01191   typedef Cgu::SharedLockPtr<T> argument_type;
01192   result_type operator()(const argument_type& s) const {
01193     // this is fine: std::hash structs do not normally contain data and
01194     // std::hash<T*> certainly won't, so we don't have overhead constructing
01195     // std::hash<T*> on the fly
01196     return std::hash<T*>()(s.get());
01197   }
01198 };
01199 } // namespace std
01200 #endif // CGU_USE_SMART_PTR_COMPARISON
01201 
01202 #endif