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