c++-gtk-utils

shared_handle.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_HANDLE_H
00040 #define CGU_SHARED_HANDLE_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 // SharedLockHandle class (however, if wanted, this is best left for
00045 // definition in the user code)
00046 /* #define CGU_SHARED_LOCK_HANDLE_USE_MUTEX 1 */
00047 
00048 #include <exception>
00049 #include <new>
00050 #include <functional> // for std::less and std::hash<T*>
00051 #include <utility>    // for std::swap
00052 #include <cstddef>    // for std::size_t
00053 #include <cstdlib>
00054 
00055 #include <glib.h>
00056 
00057 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
00058 #include <c++-gtk-utils/mutex.h>
00059 #endif
00060 
00061 #include <c++-gtk-utils/cgu_config.h>
00062 
00063 /**
00064  * @addtogroup handles handles and smart pointers
00065  */
00066 
00067 namespace Cgu {
00068 
00069 /**
00070  * @class SharedHandle shared_handle.h c++-gtk-utils/shared_handle.h
00071  * @brief This is a generic class for managing the lifetime of objects
00072  * allocated on freestore.
00073  * @ingroup handles
00074  * @sa SharedLockHandle
00075  * @sa ScopedHandle
00076  * @sa SharedHandleError
00077  * @sa GcharSharedHandle
00078  * @sa GerrorSharedHandle
00079  * @sa StandardArrayDelete CFree GFree GerrorFree GSliceFree GSliceFreeSize GSliceDestroy
00080  *
00081  * The SharedHandle class is similar to the SharedPtr class (it keeps
00082  * a reference count and deletes the handled object when the count
00083  * reaches 0), but it does not have pointer semantics.  Accordingly,
00084  * it can be used to manage the memory of arrays and other objects
00085  * allocated on the heap.
00086  *
00087  * Because it is useful with arrays, by default it deallocates memory
00088  * using C++ delete[].  However, if a SharedHandle object is passed a
00089  * function object type as a second template argument when
00090  * instantiated, it will use that function object to delete memory.
00091  * This enables it to handle the memory of any object, such as objects
00092  * to be deleted using std::free() or Glib's g_free(), g_list_free()
00093  * or g_slice_free().  Instances (such as @ref GcharScopedHandleAnchor
00094  * "GcharScopedHandle", @ref GcharSharedHandleAnchor
00095  * "GcharSharedHandle", @ref GerrorSharedHandleAnchor
00096  * "GerrorSharedHandle" and @ref GerrorScopedHandleAnchor
00097  * "GerrorScopedHandle") typdef'ed for particular deleters can
00098  * conveniently manage objects of any kind.
00099  *
00100  * To reflect the fact that it is just a handle for a pointer, it has
00101  * different instantiation semantics from a SharedPtr object.  A
00102  * SharedPtr object is instantiated using this syntax:
00103  *
00104  * @code SharedPtr<ObjType> sh_ptr(new ObjType); @endcode
00105  *
00106  * A SharedHandle is instantiated using this syntax (note that the
00107  * instantiated handle is for type T* and not T):
00108  *
00109  * @code SharedHandle<ObjType*> sh_handle(new ObjType[n]); @endcode
00110  *
00111  *
00112  * Apart from the operatorT() type conversion operator (which returns
00113  * the underlying pointer), the only other method to obtain the
00114  * underlying pointer is the get() method.  If the object referenced
00115  * is an array allocated on the heap, to use indexing you could either
00116  * do this:
00117  *
00118  * @code
00119  * using namespace Cgu;
00120  * SharedHandle<char*> handle(new char[10]);
00121  * handle.get()[0] = 'a';
00122  * std::cout << handle.get()[0] << std::endl;
00123  * @endcode
00124  *
00125  * or this:
00126  *
00127  * @code
00128  * using namespace Cgu;
00129  * SharedHandle<char*> handle(new char[10]);
00130  * handle[0] = 'a';
00131  * std::cout << handle[0] << std::endl;
00132  * @endcode
00133  *
00134  * There is also a SharedLockHandle class, which has a thread-safe
00135  * reference count, and a ScopedHandle class, which deletes its object
00136  * as soon as it goes out of scope.  A ScopedHandle class can be
00137  * viewed as a SharedHandle which cannot be assigned to or used as the
00138  * argument to a copy constructor and therefore which cannot have a
00139  * reference count of more than 1. It is used where, if you wanted
00140  * pointer semantics, you might use a const std::auto_ptr<>.
00141  *
00142  * SharedHandle objects can be instantiated for pointers to constant
00143  * objects (such as SharedHandle<const char*>), provided the deleter
00144  * functor will take such pointers.
00145  *
00146  * This library provides StandardArrayDelete, CFree, GFree,
00147  * GerrorFree, GSliceFree, GSliceFreeSize and GSliceDestroy deleter
00148  * functors, which can be used as the second template parameter of the
00149  * SharedHandle class.  As mentioned above, StandardArrayDelete is the
00150  * default, and some typedef'ed instances of SharedHandle for gchar
00151  * (with the GFree deleter) and for GError (with the GerrorFree
00152  * deleter) are provided.
00153  *
00154  * @b Comparison @b with @b std::shared_ptr
00155  *
00156  * Although the semantics of std::shared_ptr in C++11 are not
00157  * particularly suited to managing either arrays or C objects with
00158  * accessor functions (such as in glib), most of the things that can
00159  * be done by this class can be done by using std::shared_ptr with a
00160  * specialised deleter.  However, this class is retained in the
00161  * c++-gtk-utils library not only to retain compatibility with series
00162  * 1.2 of the library, but also to cater for some cases not met (or
00163  * not so easily met) by std::shared_ptr:
00164  *
00165  * (i) The Cgu::SharedHandle class takes its deleter as a template
00166  * parameter, which means that typedefs can be used to enable handles
00167  * for particular deleters to be easily created (and as mentioned,
00168  * this library provides a number of pre-formed deleter functors and
00169  * typedefs for them).  With std::shared_ptr, custom deleters must be
00170  * passed to the shared_ptr constructor on every occasion a shared_ptr
00171  * is constructed to manage a new object (and they cannot be templated
00172  * as a typedef).
00173  *
00174  * (ii) Glib memory slices provide an efficient small object allocator
00175  * (they are likely to be significantly more efficient than global
00176  * operator new()/new[](), which generally hand off to malloc(), and
00177  * whilst malloc() is good for large block allocations it is generally
00178  * poor as a small object allocator).  Internal Cgu::SharedHandle
00179  * allocation using glib memory slices can be achieved by compiling
00180  * the library with the --with-glib-memory-slices-no-compat
00181  * configuration option.
00182  *
00183  * (iii) If glib memory slices are not used (which do not throw),
00184  * constructing a shared pointer for a new managed object (or calling
00185  * reset() for a new managed object) might throw if internal
00186  * allocation fails.  Although by default the Cgu::SharedHandle
00187  * implementation will delete the new managed object in such a case,
00188  * it also provides an alternative constructor and reset() method
00189  * which instead enable the new object to be accessed via the thrown
00190  * exception object so that user code can decide what to do;
00191  * std::shared_ptr deletes the new object in every case.
00192  *
00193  * (iv) A user can explicitly state whether the shared handle object
00194  * is to have atomic increment and decrement-and-test with respect to
00195  * the reference count so that the reference count is thread safe
00196  * ('no' in the case of Cgu::SharedHandle, and 'yes' in the case of
00197  * Cgu::SharedLockHandle).  Using atomic functions is unnecessary if
00198  * the managed object concerned is only addressed in one thread (and
00199  * might cause unwanted cache flushing in certain circumstances).
00200  * std::shared_ptr will generally always use atomic functions with
00201  * respect to its reference count in a multi-threaded program.
00202  *
00203  * In favour of std::shared_ptr, it has an associated std::weak_ptr
00204  * class, which Cgu::SharedHandle does not (there is a
00205  * Cgu::GobjWeakHandle class, but that is cognate with Cgu::GobjHandle
00206  * and is only usable with GObjects).
00207  */
00208 
00209 /********************* here are some deleter classes *******************/
00210 
00211 /**
00212  * @class StandardArrayDelete shared_handle.h c++-gtk-utils/shared_handle.h
00213  * @brief A deleter functor for use as the second (Dealloc) template
00214  * parameter of the SharedHandle, SharedLockHandle or ScopedHandle
00215  * template classes, which calls the C++ delete[] expression.
00216  * @ingroup handles
00217  * @details This functor enables those classes to manage arrays
00218  * created with the new expression.  It is the default type of the
00219  * second template paramenter of those classes.
00220  */
00221 template <class T> class StandardArrayDelete {
00222 public:
00223   void operator()(T obj) {
00224     delete[] obj;
00225   }
00226 };
00227 
00228 /**
00229  * @class CFree shared_handle.h c++-gtk-utils/shared_handle.h
00230  * @brief A deleter functor for use as the second (Dealloc) template
00231  * parameter of the SharedHandle, SharedLockHandle or ScopedHandle
00232  * template classes, which calls std::free.
00233  * @ingroup handles
00234  * @details This functor enables those classes to manage memory
00235  * allocated with std::malloc(), std::calloc() and std::realloc().
00236  */
00237 class CFree {
00238 public:
00239   void operator()(const void* obj) {
00240     std::free(const_cast<void*>(obj));
00241   }
00242 };
00243 
00244 /**
00245  * @class GFree shared_handle.h c++-gtk-utils/shared_handle.h
00246  * @brief A deleter functor for use as the second (Dealloc) template
00247  * parameter of the SharedHandle, SharedLockHandle or ScopedHandle
00248  * template classes, which calls glib's g_free().
00249  * @ingroup handles
00250  * @details This functor enables those classes to manage memory
00251  * allocated by glib or gtk+ functions which requires to be freed with
00252  * g_free().  It is used in the typedefs @ref GcharSharedHandleAnchor
00253  * "GcharSharedHandle" and @ref GcharScopedHandleAnchor
00254  * "GcharScopedHandle".
00255  */
00256 class GFree {
00257 public:
00258   void operator()(const void* obj) {
00259     g_free(const_cast<void*>(obj));
00260   }
00261 };
00262 
00263 /**
00264  * @class GSliceFree shared_handle.h c++-gtk-utils/shared_handle.h
00265  * @brief A deleter functor for use as the second (Dealloc) template
00266  * parameter of the SharedHandle, SharedLockHandle or ScopedHandle
00267  * template classes, which calls glib's g_slice_free1().
00268  * @ingroup handles
00269  *
00270  * @details This functor enables those classes to manage a memory
00271  * block allocated using glib memory slices.  The managed memory block
00272  * to be deleted by the GSliceFree functor must have the same size as
00273  * the size of the object for which the functor is instantiated by
00274  * pointer, as for example as allocated with the g_slice_new,
00275  * g_slice_new0 or g_slice_dup macros (in other words, the GSliceFree
00276  * template parameter must match the argument passed to those macros):
00277  * see the example below.  Use GSliceFreeSize where it is necessary or
00278  * more convenient to have the size of the block to be freed as the
00279  * template parameter.  Use GSliceDestroy where the memory holds a C++
00280  * object constructed in the memory by the global placement new
00281  * expression.
00282  *
00283  * The type of the template argument for the functor is a pointer to
00284  * the managed type: it is the same as the first template argument of
00285  * the relevant SharedHandle, SharedLockHandle or ScopedHandle object.
00286  * For example:
00287  *
00288  * @code
00289  *   using namespace Cgu;
00290  *   SharedHandle<MyStruct*, GSliceFree<MyStruct*> > h(g_slice_new(MyStruct));
00291  *   ...
00292  * @endcode
00293  *
00294  * The availability of this functor is not dependent on the library
00295  * having been installed with the --with-glib-memory-slices-compat or
00296  * --with-glib-memory-slices-no-compat configuration option (see @ref
00297  * Memory for further details of those options).
00298  */
00299 template <class T> class GSliceFree {
00300 public:
00301   void operator()(T obj) {
00302     g_slice_free1(sizeof(*obj), (void*)obj);
00303   }
00304 };
00305 
00306 /**
00307  * @class GSliceDestroy shared_handle.h c++-gtk-utils/shared_handle.h
00308  * @brief A deleter functor for use as the second (Dealloc) template
00309  * parameter of the SharedHandle, SharedLockHandle or ScopedHandle
00310  * template classes, which calls glib's g_slice_free1(), but before
00311  * doing so also explicitly calls the destructor of a C++ object
00312  * constructed in the memory.
00313  * @ingroup handles
00314  *
00315  * @details The managed memory block to be deleted by the
00316  * GSliceDestroy functor must have the same size as the size of the
00317  * object for which the functor is instantiated by pointer, as for
00318  * example as allocated with the g_slice_new or g_slice_new0 macros
00319  * (in other words, the GSliceDestroy template parameter must match
00320  * the argument passed to those macros), and the memory block must
00321  * have had that object constructed in it with the global placement
00322  * new expression: see the example below.  Sometimes it is more
00323  * convenient to implement C++ objects in glib memory slices that way,
00324  * rather than to have custom new and delete member operators of the
00325  * classes concerned which use glib's g_slice_*().  However, a
00326  * SharedHandle class with a GSliceDestroy deleter is not as easy to
00327  * use as the SharedPtr class, as SharedHandle has no operator*() nor
00328  * operator->() method (the get() method would have to be used to
00329  * obtain the underlying pointer).
00330  *
00331  * One consequence of the static sizing (and so typing) of memory
00332  * slices is that a GSliceDestroy object instantiated for the
00333  * management of a particular class must not be used by a
00334  * SharedHandle, SharedLockHandle or ScopedHandle object which
00335  * attempts to manage a class derived from it.  This comes back to the
00336  * point that the GSliceDestroy template parameter must match the
00337  * argument passed to the g_slice_new or g_slice_new0 macros.
00338  *
00339  * The type of the template argument for the functor is a pointer to
00340  * the managed type: it is the same as the first template argument of
00341  * the relevant SharedHandle, SharedLockHandle or ScopedHandle object.
00342  * For example, to construct a SharedHandle managing an object of type
00343  * MyClass to be constructed in a glib memory slice in an exception
00344  * safe way:
00345  *
00346  * @code
00347  *   using namespace Cgu;
00348  *   SharedHandle<MyClass*, GSliceDestroy<MyClass*> > h; // won't throw
00349  *   { // scope block for p variable
00350  *     MyClass* p = g_slice_new(MyClass);
00351  *     try {new(p) MyClass;}                             // MyClass constructor might throw
00352  *     catch(...) {
00353  *       g_slice_free(MyClass, p);
00354  *       throw;
00355  *     }
00356  *     h.reset(p);                                       // might throw but if so cleans up
00357  *   }
00358  *   ...
00359  * @endcode
00360  *
00361  * The availability of this functor is not dependent on the library
00362  * having been installed with the --with-glib-memory-slices-compat or
00363  * --with-glib-memory-slices-no-compat configuration option (see @ref
00364  * Memory for further details of those options).
00365  */
00366 template <class T> class GSliceDestroy {
00367   template <class U> void destroy(U& obj) {obj.~U();}
00368 public:
00369   void operator()(T obj) {
00370     destroy(*obj);
00371     g_slice_free1(sizeof(*obj), (void*)obj);
00372   }
00373 };
00374 
00375 /**
00376  * @class GSliceFreeSize shared_handle.h c++-gtk-utils/shared_handle.h
00377  * @brief A deleter functor for use as the second (Dealloc) template
00378  * parameter of the SharedHandle, SharedLockHandle or ScopedHandle
00379  * template classes, which calls glib's g_slice_free1().
00380  * @ingroup handles
00381  *
00382  * @details This functor enables those classes to manage memory
00383  * allocated with g_slice_alloc(), g_slice_alloc0() or g_slice_copy().
00384  * It is an alternative to using GSliceFree where, instead of the
00385  * template parameter being a pointer to a particular managed type,
00386  * the size of the memory block to be freed is passed, so enabling it
00387  * to be more conveniently used to free memory containing arrays of
00388  * built-in types or of PODSs.  Use GSliceDestroy where the memory
00389  * holds a C++ object constructed in the memory by the global
00390  * placement new expression.
00391  * 
00392  * The type of the template argument for the functor is an integer
00393  * type (gsize) and is the size of the block to be managed.  For
00394  * example:
00395  *
00396  * @code
00397  *   using namespace Cgu;
00398  *   SharedHandle<char*, GSliceFreeSize<10> > h(static_cast<char*>(g_slice_alloc(10)));
00399  *   ...
00400  * @endcode
00401  *
00402  * The availability of this functor is not dependent on the library
00403  * having been installed with the --with-glib-memory-slices-compat or
00404  * --with-glib-memory-slices-no-compat configuration option (see @ref
00405  * Memory for further details of those options).
00406  */
00407 template <gsize block_size> class GSliceFreeSize {
00408 public:
00409   void operator()(const void* obj) {
00410     g_slice_free1(block_size, const_cast<void*>(obj));
00411   }
00412 };
00413 
00414 /*
00415  * we could provide a functor class for
00416  * g_slice_free_chain_with_offset() such as:
00417  *
00418  * template <class T, gsize offset> class GSliceFreeChain {
00419  *   public:
00420  *   void operator()(T obj) {
00421  *     g_slice_free_chain_with_offset(sizeof(*obj), (void*)obj, offset);
00422  *   }
00423  * };
00424  *
00425  * However, this is not going to be particularly useful because the
00426  * G_STRUCT_OFFSET macro and/or C's offsetof macro, needed to provide
00427  * the value for the offset parameter, do not work for other than
00428  * PODSs.  g_slice_free_chain_with_offset() is intended for internal
00429  * implementations and in the event of a user wanting such memory
00430  * management it is best achieved by having custom new[] and delete[]
00431  * member operators of the class concerned which use glib's
00432  * g_slice_*() directly.
00433  */
00434 
00435 /********************* define some typedefs for Glib ******************/
00436 
00437 template <class T, class Dealloc> class SharedHandle;
00438 template <class T, class Dealloc> class ScopedHandle;
00439 
00440 /**
00441  * @typedef GcharSharedHandle.
00442  * @brief A handle comprising a typed instance of the SharedHandle
00443  * class for gchar* arrays and strings
00444  * @anchor GcharSharedHandleAnchor
00445  * @ingroup handles
00446  * \#include <c++-gtk-utils/shared_handle.h>
00447  */
00448 typedef SharedHandle<gchar*, GFree> GcharSharedHandle;
00449 
00450 /**
00451  * @typedef GcharScopedHandle.
00452  * @brief A handle comprising a typed instance of the ScopedHandle
00453  * class for gchar* arrays and strings
00454  * @anchor GcharScopedHandleAnchor
00455  * @ingroup handles
00456  * \#include <c++-gtk-utils/shared_handle.h>
00457 */
00458 typedef ScopedHandle<gchar*, GFree> GcharScopedHandle;
00459 
00460 
00461 /******************* now the handle class definitions *****************/
00462 
00463 /**
00464  * @class SharedHandleError shared_handle.h c++-gtk-utils/shared_handle.h
00465  * @brief This is an exception struct thrown as an alternative to
00466  * deleting a managed object when internal memory allocation for
00467  * SharedHandle or SharedLockHandle fails in their reset() method or
00468  * in their constructor which takes a pointer.
00469  * @sa SharedHandle SharedLockHandle SharedHandleAllocFail
00470  * @ingroup handles
00471  *
00472  * This is an exception struct thrown as an alternative to deleting a
00473  * managed object when SharedHandle<T>::SharedHandle(T),
00474  * SharedLockHandle<T>::SharedLockHandle(T), SharedHandle<T>::reset(T)
00475  * or SharedLockHandle<T>::reset(T) would otherwise throw
00476  * std::bad_alloc.  To make those methods do that,
00477  * Cgu::SharedHandleAllocFail::leave is passed as their second
00478  * argument.
00479  *
00480  * If the exception is thrown, the struct has a member 'obj' of type
00481  * T, which is a pointer to the object or array originally passed to
00482  * those methods, so the user can deal with it appropriately.  This
00483  * enables the result of the new expression to be passed directly as
00484  * the argument to those methods without giving rise to a resource
00485  * leak, as in:
00486  * 
00487  * @code
00488  * using namespace Cgu;
00489  * SharedHandle<T*> s;                                // doesn't throw
00490  * try {
00491  *   s.reset(new T[2], SharedHandleAllocFail::leave); // both T allocation and reset() might throw
00492  * }
00493  * catch (std::bad_alloc&) {
00494  *   ...
00495  * }
00496  * catch (SharedHandleError<T*>& e) {
00497  *   e.obj[0].do_something();
00498  *   e.obj[1].do_something();
00499  *   ...
00500  * }
00501  * ...
00502  * @endcode 
00503  *
00504  * As above, a catch block will need to deal with std::bad_alloc (if
00505  * the call to the new expression when creating the T object fails)
00506  * as well as SharedHandleError (if the call to the new expression in
00507  * the reset() method fails after a valid T object has been
00508  * constructed).
00509  */
00510 
00511 template <class T> struct SharedHandleError: public std::exception {
00512   T obj;
00513   virtual const char* what() const throw() {return "SharedHandleError\n";}
00514   SharedHandleError(T p): obj(p) {}
00515 };
00516 
00517 /**
00518  * enum Cgu::SharedHandleAllocFail::Leave
00519  * The enumerator Cgu::SharedHandleAllocFail::leave is passed as the
00520  * second argument of the reset() method of SharedHandle or
00521  * SharedLockHandle in order to prevent the method deleting the object
00522  * passed to it if reset() fails internally because of memory
00523  * exhaustion.
00524  * @ingroup handles
00525  */
00526 namespace SharedHandleAllocFail {
00527  enum Leave {leave};
00528 }
00529 
00530 template <class T, class Dealloc = StandardArrayDelete<T>> class SharedHandle {
00531 
00532   Dealloc deleter;
00533 
00534 #ifndef DOXYGEN_PARSING
00535   struct RefItems {
00536     unsigned int* ref_count_p;
00537     T obj;
00538   } ref_items;
00539 #endif
00540 
00541   void unreference() {
00542     if (!ref_items.ref_count_p) return;
00543     --(*ref_items.ref_count_p);
00544     if (*ref_items.ref_count_p == 0) {
00545 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
00546       g_slice_free(unsigned int, ref_items.ref_count_p);
00547 #else
00548       delete ref_items.ref_count_p;
00549 #endif
00550       deleter(ref_items.obj);
00551     }
00552   }
00553 
00554   void reference() {
00555     if (!ref_items.ref_count_p) return;
00556     ++(*ref_items.ref_count_p);
00557   }
00558 
00559 public:
00560 /**
00561  * Constructor taking an unmanaged object.
00562  * @param ptr The object which the SharedHandle is to manage (if
00563  * any).
00564  * @exception std::bad_alloc This constructor will not throw if the
00565  * 'ptr' argument has a NULL value (the default), otherwise it might
00566  * throw std::bad_alloc if memory is exhausted and the system throws
00567  * in that case.  If such an exception is thrown, this constructor is
00568  * exception safe (it does not leak resources), but as well as
00569  * cleaning itself up this constructor will also delete the managed
00570  * object passed to it to avoid a memory leak.  If such automatic
00571  * deletion is not wanted in that case, use the version of this
00572  * constructor taking a Cgu::SharedHandleAllocFail::Leave tag argument.
00573  * @note std::bad_alloc will not be thrown if the library has been
00574  * installed using the --with-glib-memory-slices-no-compat
00575  * configuration option: instead glib will terminate the program if it
00576  * is unable to obtain memory from the operating system.
00577  */
00578   explicit SharedHandle(T ptr = 0) {
00579 
00580     if ((ref_items.obj = ptr)) { // not NULL
00581 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
00582       ref_items.ref_count_p = g_slice_new(unsigned int);
00583       *ref_items.ref_count_p = 1;
00584 #else
00585       try {
00586         ref_items.ref_count_p = new unsigned int(1);
00587       }
00588       catch (...) {
00589         deleter(ptr); // if allocating the int referenced by ref_items.ref_count_p
00590                       // has failed then delete the object to be referenced to
00591                       // avoid a memory leak
00592         throw;
00593       }
00594 #endif
00595     }
00596     else ref_items.ref_count_p = 0;
00597   }
00598 
00599 /**
00600  * Constructor taking an unmanaged object.
00601  * @param ptr The object which the SharedHandle is to manage
00602  * @param tag Passing the tag emumerator
00603  * Cgu::SharedHandleAllocFail::leave causes this constructor not to
00604  * delete the new managed object passed as the 'ptr' argument in the
00605  * event of internal allocation in this method failing because of
00606  * memory exhaustion (in that event, Cgu::SharedHandleError will be
00607  * thrown).
00608  * @exception Cgu::SharedHandleError This constructor might throw
00609  * Cgu::SharedHandleError if memory is exhausted and the system would
00610  * otherwise throw std::bad_alloc in that case.  This constructor is
00611  * exception safe (it does not leak resources), and if such an
00612  * exception is thrown it will clean itself up, but it will not
00613  * attempt to delete the new managed object passed to it.  Access to
00614  * the object passed to the 'ptr' argument can be obtained via the
00615  * thrown Cgu::SharedHandleError object.
00616  * @note 1. On systems with over-commit/lazy-commit combined with
00617  * virtual memory (swap), it is rarely useful to check for memory
00618  * exhaustion, so in those cases this version of the constructor will
00619  * not be useful.
00620  * @note 2. If the library has been installed using the
00621  * --with-glib-memory-slices-no-compat configuration option this
00622  * version of the constructor will also not be useful: instead glib
00623  * will terminate the program if it is unable to obtain memory from
00624  * the operating system.
00625  */
00626   SharedHandle(T ptr, Cgu::SharedHandleAllocFail::Leave tag) {
00627 
00628     if ((ref_items.obj = ptr)) { // not NULL
00629 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
00630       ref_items.ref_count_p = g_slice_new(unsigned int);
00631       *ref_items.ref_count_p = 1;
00632 #else
00633       try {
00634         ref_items.ref_count_p = new unsigned int(1);
00635       }
00636       catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly
00637         throw SharedHandleError<T>(ptr);
00638       }
00639 #endif
00640     }
00641     else ref_items.ref_count_p = 0;
00642   }
00643 
00644 /**
00645  * Causes the SharedHandle to cease to manage its managed object (if
00646  * any), deleting it if this is the last SharedHandle object managing
00647  * it.  If the argument passed is not NULL, the SharedHandle object
00648  * will manage the new object passed (which must not be managed by any
00649  * other SharedHandle object).  This method is exception safe, but see
00650  * the comments below on std::bad_alloc.
00651  * @param ptr NULL (the default), or a new unmanaged object to manage.
00652  * @exception std::bad_alloc This method will not throw if the 'ptr'
00653  * argument has a NULL value (the default) and the destructor of a
00654  * managed object does not throw, otherwise it might throw
00655  * std::bad_alloc if memory is exhausted and the system throws in that
00656  * case.  Note that if such an exception is thrown then this method
00657  * will do nothing (it is strongly exception safe and will continue to
00658  * manage the object it was managing prior to the call), except that
00659  * it will delete the new managed object passed to it to avoid a
00660  * memory leak.  If such automatic deletion in the event of such an
00661  * exception is not wanted, use the reset() method taking a
00662  * Cgu::SharedHandleAllocFail::Leave tag type as its second argument.
00663  * @note std::bad_alloc will not be thrown if the library has been
00664  * installed using the --with-glib-memory-slices-no-compat
00665  * configuration option: instead glib will terminate the program if it
00666  * is unable to obtain memory from the operating system.
00667  */
00668   void reset(T ptr = 0) {
00669     SharedHandle tmp(ptr);
00670     std::swap(ref_items, tmp.ref_items);
00671   }
00672 
00673 /**
00674  * Causes the SharedHandle to cease to manage its managed object (if
00675  * any), deleting it if this is the last SharedHandle object managing
00676  * it.  The SharedHandle object will manage the new object passed
00677  * (which must not be managed by any other SharedHandle object).  This
00678  * method is exception safe, but see the comments below on
00679  * Cgu::SharedHandleError.
00680  * @param ptr A new unmanaged object to manage (if no new object is to
00681  * be managed, use the version of reset() taking a default value of
00682  * NULL).
00683  * @param tag Passing the tag emumerator
00684  * Cgu::SharedHandleAllocFail::leave causes this method not to delete
00685  * the new managed object passed as the 'ptr' argument in the event of
00686  * internal allocation in this method failing because of memory
00687  * exhaustion (in that event, Cgu::SharedHandleError will be thrown).
00688  * @exception Cgu::SharedHandleError This method might throw
00689  * Cgu::SharedHandleError if memory is exhausted and the system would
00690  * otherwise throw std::bad_alloc in that case.  Note that if such an
00691  * exception is thrown then this method will do nothing (it is
00692  * strongly exception safe and will continue to manage the object it
00693  * was managing prior to the call), and it will not attempt to delete
00694  * the new managed object passed to it.  Access to the object passed
00695  * to the 'ptr' argument can be obtained via the thrown
00696  * Cgu::SharedHandleError object.
00697  * @note 1. On systems with over-commit/lazy-commit combined with
00698  * virtual memory (swap), it is rarely useful to check for memory
00699  * exhaustion, so in those cases this version of the reset() method
00700  * will not be useful.
00701  * @note 2. If the library has been installed using the
00702  * --with-glib-memory-slices-no-compat configuration option this
00703  * version of the reset() method will also not be useful: instead glib
00704  * will terminate the program if it is unable to obtain memory from
00705  * the operating system.
00706  */
00707   void reset(T ptr, Cgu::SharedHandleAllocFail::Leave tag) {
00708     SharedHandle tmp(ptr, tag);
00709     std::swap(ref_items, tmp.ref_items);
00710   }
00711 
00712  /**
00713   * The copy constructor does not throw.
00714   * @param sh_hand The handle to be copied.
00715   */
00716   SharedHandle(const SharedHandle& sh_hand) {
00717     ref_items = sh_hand.ref_items;
00718     reference();
00719   }
00720 
00721  /**
00722   * The move constructor does not throw.  It has move semantics.
00723   * @param sh_hand The handle to be moved.
00724   */
00725   SharedHandle(SharedHandle&& sh_hand) {
00726     ref_items = sh_hand.ref_items;
00727     sh_hand.ref_items.ref_count_p = 0;
00728     sh_hand.ref_items.obj = 0;
00729   }
00730 
00731  /**
00732   * This method (and so copy or move assignment) does not throw unless
00733   * the destructor of a managed object throws.
00734   * @param sh_hand the assignor.
00735   * @return The SharedHandle object after assignment.
00736   */
00737   // having a value type as the argument, rather than reference to const
00738   // and then initialising a tmp object, gives the compiler more scope
00739   // for optimisation, and also caters for r-values without a separate
00740   // overload
00741   SharedHandle& operator=(SharedHandle sh_hand) {
00742     std::swap(ref_items, sh_hand.ref_items);
00743     return *this;
00744   }
00745 
00746  /**
00747   * This method does not throw.
00748   * @return A pointer to the handled object (or NULL if none is
00749   * handled).
00750   */
00751   T get() const {return ref_items.obj;}
00752 
00753  /**
00754   * This method does not throw.
00755   * @return A pointer to the handled object (or NULL if none is
00756   * handled).
00757   */
00758   operator T() const {return ref_items.obj;}
00759 
00760  /**
00761   * This method does not throw.
00762   * @return The number of SharedHandle objects referencing the managed
00763   * object (or 0 if none is managed by this SharedHandle).
00764   */
00765   unsigned int get_refcount() const {return (ref_items.ref_count_p) ? *ref_items.ref_count_p : 0;}
00766 
00767  /**
00768   * The destructor does not throw unless the destructor of a handled
00769   * object throws - that should never happen.
00770   */
00771   ~SharedHandle() {unreference();}
00772 };
00773 
00774 /**
00775  * @class ScopedHandle shared_handle.h c++-gtk-utils/shared_handle.h
00776  * @brief This is a generic scoped class for managing the lifetime of objects
00777  * allocated on freestore.
00778  * @ingroup handles
00779  * @sa SharedHandle SharedLockHandle SharedHandleError
00780  * @sa StandardArrayDelete CFree GFree GerrorFree GSliceFree GSliceFreeSize GSliceDestroy
00781  *
00782  * This class deletes its object as soon as it goes out of scope.  It
00783  * can be viewed as a SharedHandle which cannot be assigned to or used
00784  * as the argument to a copy constructor and therefore which cannot
00785  * have a reference count of more than 1.
00786  *
00787  * ScopedHandle objects can be instantiated for pointers to constant
00788  * objects (such as ScopedHandle<const char*>), provided the deleter
00789  * functor will take such pointers.
00790  *
00791  * This library provides StandardArrayDelete, CFree, GFree,
00792  * GerrorFree, GSliceFree, GSliceFreeSize and GSliceDestroy deleter
00793  * functors, which can be used as the second template parameter of the
00794  * ScopedHandle class.  StandardArrayDelete is the default, and some
00795  * typedef'ed instances of ScopedHandle for gchar (with the GFree
00796  * deleter) and for GError (with the GerrorFree deleter) are provided:
00797  * @ref GcharScopedHandleAnchor "GcharScopedHandle" and @ref
00798  * GerrorScopedHandleAnchor "GerrorScopedHandle")
00799  *
00800  * @b Comparison @b with @b std::unique_ptr
00801  *
00802  * Although the semantics of std::unique_ptr in C++11 are not
00803  * particularly suited to managing C objects with accessor functions
00804  * (such as in glib), most of the things that can be done by this
00805  * class can be done by using std::unique_ptr with a specialised
00806  * deleter.  However, this class is retained in the c++-gtk-utils
00807  * library not only to retain compatibility with series 1.2 of the
00808  * library, but also to cater for some cases not so easily met by
00809  * std::unique_ptr:
00810  *
00811  * (i) The Cgu::ScopedHandle class takes its deleter as a template
00812  * parameter, which means that typedefs can be used to enable handles
00813  * for particular deleters to be easily created (and as mentioned,
00814  * this library provides a number of pre-formed deleter functors and
00815  * typedefs for them).  With std::unique_ptr, custom deleters must be
00816  * passed to the unique_ptr constructor on every occasion a unique_ptr
00817  * is constructed to manage a new object (and they cannot be templated
00818  * as a typedef).
00819  *
00820  * (ii) This class provides non-move enforcement without making a
00821  * const instance of it.  A const std::unique_ptr cannot be moved from
00822  * or to, but then it cannot have release() or reset() called for it
00823  * either.
00824  */
00825 
00826 template <class T, class Dealloc = StandardArrayDelete<T>> class ScopedHandle {
00827   Dealloc deleter;
00828   T obj;
00829 public:
00830 /**
00831  * This class cannot be copied.  The copy constructor is deleted.
00832  */
00833   ScopedHandle(const ScopedHandle&) = delete;
00834 
00835 /**
00836  * This class cannot be copied.  The assignment operator is deleted.
00837  */
00838   ScopedHandle& operator=(const ScopedHandle&) = delete;
00839 
00840 /**
00841  * The constructor does not throw.
00842  * @param ptr The object which the ScopedHandle is to manage (if
00843  * any).
00844  *
00845  * ScopedHandle objects can be instantiated for pointers to constant
00846  * objects (such as SharedHandle<const char*>), provided the deleter
00847  * functor will take such pointers.
00848  */
00849   explicit ScopedHandle(T ptr = 0): obj(ptr) {}
00850 
00851 /**
00852  * Causes the ScopedHandle to delete its managed object (if any), and
00853  * if the argument passed is not NULL, the ScopedHandle object will
00854  * manage the new object passed (which must not be managed by any
00855  * other ScopedHandle object).  This method does not throw (assuming
00856  * the destructor of a managed object does not throw).
00857  * @param ptr NULL (the default), or a new unmanaged object to manage.
00858  */
00859   void reset(T ptr = 0) {
00860     std::swap(obj, ptr);
00861     if (ptr) deleter(ptr); // ptr now points to the original managed object
00862   }
00863 
00864 /**
00865  * Causes the ScopedHandle to cease to manage the handled object, but
00866  * does not delete that object.  This method does not throw.
00867  * @return A pointer to the previously handled object (or NULL if none
00868  * was handled).
00869  */
00870   T release() {T tmp = obj; obj = 0; return tmp;}
00871 
00872 /**
00873  * This method does not throw.
00874  * @return A pointer to the handled object (or NULL if none is
00875  * handled).
00876  */
00877   T get() const {return obj;}
00878 
00879 /**
00880  * This method does not throw.
00881  * @return A pointer to the handled object (or NULL if none is
00882  * handled).
00883  */
00884   operator T() const {return obj;}
00885 
00886 /**
00887  * The destructor does not throw unless the destructor of a handled
00888  * object throws - that should never happen.
00889  */
00890   ~ScopedHandle() {if (obj) deleter(obj);}
00891 };
00892 
00893 
00894 /**
00895  * @class SharedLockHandle shared_handle.h c++-gtk-utils/shared_handle.h
00896  * @brief This is a generic class for managing the lifetime of objects
00897  * allocated on freestore, with a thread safe reference count..
00898  * @ingroup handles
00899  * @sa SharedHandle ScopedHandle SharedHandleError
00900  * @sa StandardArrayDelete CFree GFree GerrorFree GSliceFree GSliceFreeSize GSliceDestroy
00901  *
00902  * Class SharedLockHandle is a version of the SharedHandle class which
00903  * includes locking so that it can be accessed in multiple threads
00904  * (although the word Lock is in the title, by default it uses glib
00905  * atomic functions to access the reference count rather than a mutex,
00906  * so the overhead should be very small).  Note that only the
00907  * reference count is protected, so this is thread safe in the sense
00908  * in which a raw pointer is thread safe.  A shared handle accessed in
00909  * one thread referencing a particular object is thread safe as
00910  * against another shared handle accessing the same object in a
00911  * different thread.  It is thus suitable for use in different Std C++
00912  * containers which exist in different threads but which contain
00913  * shared objects by reference.  But:
00914  *
00915  * 1.  If the referenced object is to be modified in one thread and
00916  *     read or modified in another thread an appropriate mutex for the
00917  *     referenced object is required (unless that referenced object
00918  *     does its own locking).
00919  *
00920  * 2.  If the same instance of shared handle is to be modified in one
00921  *     thread (by assigning to the handle so that it references a
00922  *     different object, or by moving from it), and copied (assigned
00923  *     from or used as the argument of a copy constructor), accessed,
00924  *     destroyed or modified in another thread, a mutex for that
00925  *     instance of shared handle is required.
00926  *
00927  * 3.  Objects referenced by shared handles which are objects for
00928  *     which POSIX provides no guarantees (in the main, those which
00929  *     are not built-in types), such as strings and similar
00930  *     containers, may not support concurrent reads in different
00931  *     threads.  That depends on the library implementation concerned.
00932  *     If that is the case, a mutex for the referenced object will
00933  *     also be required when reading any given instance of such an
00934  *     object in more than one thread by dereferencing any shared
00935  *     handles referencing it (and indeed, when not using shared
00936  *     handles at all).
00937  *
00938  * SharedLockHandle objects can be instantiated for pointers to
00939  * constant objects (such as SharedLockHandle<const char*>), provided
00940  * the deleter functor will take such pointers.
00941  *
00942  * This library provides StandardArrayDelete, CFree, GFree,
00943  * GerrorFree, GSliceFree, GSliceFreeSize and GSliceDestroy deleter
00944  * functors, which can be used as the second template parameter of the
00945  * SharedLockHandle class.  StandardArrayDelete is the default.
00946  *
00947  * As mentioned, by default glib atomic functions are used to provide
00948  * thread-safe manipulation of the reference count.  However, a
00949  * library user can define the symbol CGU_SHARED_LOCK_HANDLE_USE_MUTEX
00950  * before shared_handle.h is parsed so as to use mutexes instead,
00951  * which might be useful for some debugging purposes.
00952  *
00953  * @b Comparison @b with @b std::shared_ptr
00954  *
00955  * Although the semantics of std::shared_ptr in C++11 are not
00956  * particularly suited to managing either arrays or C objects with
00957  * accessor functions (such as in glib), most of the things that can
00958  * be done by this class can be done by using std::shared_ptr with a
00959  * specialised deleter.  However, this class is retained in the
00960  * c++-gtk-utils library not only to retain compatibility with series
00961  * 1.2 of the library, but also to cater for some cases not met (or
00962  * not so easily met) by std::shared_ptr:
00963  *
00964  * (i) The Cgu::SharedLockHandle class takes its deleter as a template
00965  * parameter, which means that typedefs can be used to enable handles
00966  * for particular deleters to be easily created (and as mentioned,
00967  * this library provides a number of pre-formed deleter functors and
00968  * typedefs for them).  With std::shared_ptr, custom deleters must be
00969  * passed to the shared_ptr constructor on every occasion a shared_ptr
00970  * is constructed to manage a new object (and they cannot be templated
00971  * as a typedef).
00972  *
00973  * (ii) Glib memory slices provide an efficient small object allocator
00974  * (they are likely to be significantly more efficient than global
00975  * operator new()/new[](), which generally hand off to malloc(), and
00976  * whilst malloc() is good for large block allocations it is generally
00977  * poor as a small object allocator).  Internal Cgu::SharedLockHandle
00978  * allocation using glib memory slices can be achieved by compiling
00979  * the library with the --with-glib-memory-slices-no-compat
00980  * configuration option.
00981  *
00982  * (iii) If glib memory slices are not used (which do not throw),
00983  * constructing a shared pointer for a new managed object (or calling
00984  * reset() for a new managed object) might throw if internal
00985  * allocation fails.  Although by default the Cgu::SharedLockHandle
00986  * implementation will delete the new managed object in such a case,
00987  * it also provides an alternative constructor and reset() method
00988  * which instead enable the new object to be accessed via the thrown
00989  * exception object so that user code can decide what to do;
00990  * std::shared_ptr deletes the new object in every case.
00991  *
00992  * (iv) A user can explicitly state whether the shared handle object
00993  * is to have atomic increment and decrement-and-test with respect to
00994  * the reference count so that the reference count is thread safe
00995  * ('no' in the case of Cgu::SharedHandle, and 'yes' in the case of
00996  * Cgu::SharedLockHandle).  Using atomic functions is unnecessary if
00997  * the managed object concerned is only addressed in one thread (and
00998  * might cause unwanted cache flushing in certain circumstances).
00999  * std::shared_ptr will generally always use atomic functions with
01000  * respect to its reference count in a multi-threaded program.
01001  *
01002  * In favour of std::shared_ptr, it has an associated std::weak_ptr
01003  * class, which Cgu::SharedLockHandle does not (there is a
01004  * Cgu::GobjWeakHandle class, but that is cognate with Cgu::GobjHandle
01005  * and is only usable with GObjects).  In addition shared_ptr objects
01006  * have some atomic store, load and exchange functions provided for
01007  * them which enable concurrent modifications of the same instance of
01008  * shared_ptr in different threads to have defined results.
01009  */
01010 
01011 template <class T, class Dealloc = StandardArrayDelete<T>> class SharedLockHandle {
01012 
01013   Dealloc deleter;
01014 
01015 #ifndef DOXYGEN_PARSING
01016   struct RefItems {
01017 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
01018     Thread::Mutex* mutex_p;
01019     unsigned int* ref_count_p;
01020 #else
01021     gint* ref_count_p;
01022 #endif
01023     T obj;
01024   } ref_items;
01025 #endif
01026 
01027   // SharedLockHandle<T, Dealloc>::unreference() does not throw exceptions
01028   // because  Thread::Mutex::~Mutex(), Thread::Mutex::lock() and Thread::Mutex::unlock()
01029   // do not throw
01030   void unreference() {
01031     // we can (and should) check whether ref_items.ref_count_p is NULL without
01032     // a lock, because that member is specific to this SharedLockHandle object.
01033     // Only the integer pointed to by it is shared amongst SharedLockHandle
01034     // objects and requires locking
01035     if (!ref_items.ref_count_p) return;
01036 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
01037     ref_items.mutex_p->lock();
01038     --(*ref_items.ref_count_p);
01039     if (*ref_items.ref_count_p == 0) {
01040 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
01041       g_slice_free(unsigned int, ref_items.ref_count_p);
01042 # else
01043       delete ref_items.ref_count_p;
01044 # endif
01045       ref_items.mutex_p->unlock();
01046       delete ref_items.mutex_p;
01047       deleter(ref_items.obj);
01048     }
01049     else ref_items.mutex_p->unlock();
01050 #else
01051     if (g_atomic_int_dec_and_test(ref_items.ref_count_p)) {
01052 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
01053       g_slice_free(gint, ref_items.ref_count_p);
01054 # else
01055       delete ref_items.ref_count_p;
01056 # endif
01057       deleter(ref_items.obj);
01058     }
01059 #endif
01060   }
01061   
01062   // SharedLockHandle<T, Dealloc>::reference() does not throw exceptions because
01063   // Thread::Mutex::Lock::Lock() and Thread::Mutex::Lock::~Lock() do not throw
01064   void reference() {
01065     // we can (and should) check whether ref_items.ref_count_p is NULL without
01066     // a lock, because that member is specific to this SharedLockHandle object.
01067     // Only the integer pointed to by it is shared amongst SharedLockHandle
01068     // objects and requires locking
01069     if (!ref_items.ref_count_p) return;
01070 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
01071     Thread::Mutex::Lock lock(*ref_items.mutex_p);
01072     ++(*ref_items.ref_count_p);
01073 #else
01074     g_atomic_int_inc(ref_items.ref_count_p);
01075 #endif
01076   }
01077 
01078 public:
01079 /**
01080  * Constructor taking an unmanaged object.
01081  * @param ptr The object which the SharedLockHandle is to manage (if
01082  * any).
01083  * @exception std::bad_alloc This constructor will not throw if the
01084  * 'ptr' argument has a NULL value (the default), otherwise it might
01085  * throw std::bad_alloc if memory is exhausted and the system throws
01086  * in that case.  If such an exception is thrown, this constructor is
01087  * exception safe (it does not leak resources), but as well as
01088  * cleaning itself up this constructor will also delete the managed
01089  * object passed to it to avoid a memory leak.  If such automatic
01090  * deletion is not wanted in that case, use the version of this
01091  * constructor taking a Cgu::SharedHandleAllocFail::Leave tag
01092  * argument.
01093  * @note 1.  std::bad_alloc will not be thrown if the library has been
01094  * installed using the --with-glib-memory-slices-no-compat
01095  * configuration option: instead glib will terminate the program if it
01096  * is unable to obtain memory from the operating system.
01097  * @note 2. By default, glib atomic functions are used to provide
01098  * thread-safe manipulation of the reference count.  However, a
01099  * library user can define the symbol CGU_SHARED_LOCK_HANDLE_USE_MUTEX
01100  * before shared_handle.h is parsed so as to use mutexes instead,
01101  * which might be useful for some debugging purposes.  Were she to do
01102  * so, Cgu::Thread::MutexError might be thrown by this constructor if
01103  * initialization of the mutex fails, but it is usually not worth
01104  * checking for this.
01105  */
01106   explicit SharedLockHandle(T ptr = 0) {
01107 
01108     if ((ref_items.obj = ptr)) { // not NULL
01109 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
01110       try {
01111         ref_items.mutex_p = new Thread::Mutex;
01112       }
01113       catch (...) {
01114         deleter(ptr); // if allocating the object referenced by ref_items.mutex_p
01115                       // has failed then delete the object to be referenced to
01116                       // avoid a memory leak
01117         throw;
01118       }
01119 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
01120       ref_items.ref_count_p = g_slice_new(unsigned int);
01121       *ref_items.ref_count_p = 1;
01122 # else
01123       try {
01124         ref_items.ref_count_p = new unsigned int(1);
01125       }
01126       catch (...) {
01127         delete ref_items.mutex_p;
01128         deleter(ptr);
01129         throw;
01130       }
01131 # endif
01132 #else
01133 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
01134       ref_items.ref_count_p = g_slice_new(gint);
01135       *ref_items.ref_count_p = 1;
01136 # else
01137       try {
01138         ref_items.ref_count_p = new gint(1);
01139       }
01140       catch (...) {
01141         deleter(ptr); // if allocating the int referenced by ref_items.ref_count_p
01142                       // has failed then delete the object to be referenced to
01143                       // avoid a memory leak
01144         throw;
01145       }
01146 # endif
01147 #endif
01148     }
01149     else {
01150 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
01151       ref_items.mutex_p = 0;  // make sure the value is valid as we may assign it
01152 #endif
01153       ref_items.ref_count_p = 0;
01154     }
01155   }
01156 
01157  /**
01158  * Constructor taking an unmanaged object.
01159  * @param ptr The object which the SharedLockHandle is to manage.
01160  * @param tag Passing the tag emumerator
01161  * Cgu::SharedHandleAllocFail::leave causes this constructor not to
01162  * delete the new managed object passed as the 'ptr' argument in the
01163  * event of internal allocation in this method failing because of
01164  * memory exhaustion (in that event, Cgu::SharedHandleError will be
01165  * thrown).
01166  * @exception Cgu::SharedHandleError This constructor might throw
01167  * Cgu::SharedHandleError if memory is exhausted and the system would
01168  * otherwise throw std::bad_alloc in that case.  This constructor is
01169  * exception safe (it does not leak resources), and if such an
01170  * exception is thrown it will clean itself up, but it will not
01171  * attempt to delete the new managed object passed to it.  Access to
01172  * the object passed to the 'ptr' argument can be obtained via the
01173  * thrown Cgu::SharedHandleError object.
01174  * @note 1. On systems with over-commit/lazy-commit combined with
01175  * virtual memory (swap), it is rarely useful to check for memory
01176  * exhaustion, so in those cases this version of the constructor will
01177  * not be useful.
01178  * @note 2. If the library has been installed using the
01179  * --with-glib-memory-slices-no-compat configuration option this
01180  * version of the constructor will also not be useful: instead glib
01181  * will terminate the program if it is unable to obtain memory from
01182  * the operating system.
01183  * @note 3. By default, glib atomic functions are used to provide
01184  * thread-safe manipulation of the reference count.  However, a
01185  * library user can define the symbol CGU_SHARED_LOCK_HANDLE_USE_MUTEX
01186  * before shared_handle.h is parsed so as to use mutexes instead,
01187  * which might be useful for some debugging purposes.  Were she to do
01188  * so, Cgu::SharedHandleError might be thrown by this constructor if
01189  * initialization of the mutex fails (even if the
01190  * --with-glib-memory-slices-no-compat configuration option is
01191  * chosen), but it is usually not worth checking for such mutex
01192  * initialization failure.
01193  */
01194   SharedLockHandle(T ptr, Cgu::SharedHandleAllocFail::Leave tag) {
01195 
01196     if ((ref_items.obj = ptr)) { // not NULL
01197 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
01198       try {
01199         ref_items.mutex_p = new Thread::Mutex;
01200       }
01201       catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly
01202         throw SharedHandleError<T>(ptr);
01203       }
01204       catch (Thread::MutexError&) { // as we are not rethrowing, make NPTL friendly
01205         throw SharedHandleError<T>(ptr);
01206       }
01207 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
01208       ref_items.ref_count_p = g_slice_new(unsigned int);
01209       *ref_items.ref_count_p = 1;
01210 # else
01211       try {
01212         ref_items.ref_count_p = new unsigned int(1);
01213       }
01214       catch (std::bad_alloc&) {
01215         delete ref_items.mutex_p;
01216         throw SharedHandleError<T>(ptr);
01217       }
01218 # endif
01219 #else
01220 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
01221       ref_items.ref_count_p = g_slice_new(gint);
01222       *ref_items.ref_count_p = 1;
01223 # else
01224       try {
01225         ref_items.ref_count_p = new gint(1);
01226       }
01227       catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly
01228         throw SharedHandleError<T>(ptr);
01229       }
01230 # endif
01231 #endif
01232     }
01233     else {
01234 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
01235       ref_items.mutex_p = 0;  // make sure the value is valid as we may assign it
01236 #endif
01237       ref_items.ref_count_p = 0;
01238     }
01239   }
01240 
01241 /**
01242  * Causes the SharedLockHandle to cease to manage its managed object
01243  * (if any), deleting it if this is the last ShareLockHandle object
01244  * managing it.  If the argument passed is not NULL, the
01245  * SharedLockHandle object will manage the new object passed (which
01246  * must not be managed by any other SharedLockHandle object).
01247  * @param ptr NULL (the default), or a new unmanaged object to manage.
01248  * @exception std::bad_alloc This method will not throw if the 'ptr'
01249  * argument has a NULL value (the default) and the destructor of a
01250  * managed object does not throw, otherwise it might throw
01251  * std::bad_alloc if memory is exhausted and the system throws in that
01252  * case.  Note that if such an exception is thrown then this method
01253  * will do nothing (it is strongly exception safe and will continue to
01254  * manage the object it was managing prior to the call), except that
01255  * it will delete the new managed object passed to it to avoid a
01256  * memory leak.  If such automatic deletion in the event of such an
01257  * exception is not wanted, use the reset() method taking a
01258  * Cgu::SharedHandleAllocFail::Leave tag type as its second argument.
01259  * @note 1. std::bad_alloc will not be thrown if the library has been
01260  * installed using the --with-glib-memory-slices-no-compat
01261  * configuration option: instead glib will terminate the program if it
01262  * is unable to obtain memory from the operating system.
01263  * @note 2. By default, glib atomic functions are used to provide
01264  * thread-safe manipulation of the reference count.  However, a
01265  * library user can define the symbol CGU_SHARED_LOCK_HANDLE_USE_MUTEX
01266  * before shared_handle.h is parsed so as to use mutexes instead,
01267  * which might be useful for some debugging purposes.  Were she to do
01268  * so, Cgu::Thread::MutexError might be thrown by this method if
01269  * initialization of the mutex fails, but it is usually not worth
01270  * checking for this.
01271  * @note 3. A SharedLockHandle object protects its reference count but
01272  * not the managed object or its other internals.  The reset() method
01273  * should not be called by one thread in respect of a particular
01274  * SharedLockHandle object while another thread may be operating on,
01275  * copying or dereferencing the same instance of SharedLockHandle.  It
01276  * is thread-safe as against another instance of SharedLockHandle
01277  * managing the same object.
01278  */
01279   void reset(T ptr = 0) {
01280     SharedLockHandle tmp(ptr);
01281     std::swap(ref_items, tmp.ref_items);
01282   }
01283 
01284 /**
01285  * Causes the SharedLockHandle to cease to manage its managed object
01286  * (if any), deleting it if this is the last ShareLockHandle object
01287  * managing it.  The SharedLockHandle object will manage the new
01288  * object passed (which must not be managed by any other
01289  * SharedLockHandle object).  This method is exception safe, but see
01290  * the comments below on Cgu::SharedHandleError.
01291  * @param ptr A new unmanaged object to manage (if no new object is to
01292  * be managed, use the version of reset() taking a default value of
01293  * NULL).
01294  * @param tag Passing the tag emumerator
01295  * Cgu::SharedHandleAllocFail::leave causes this method not to delete
01296  * the new managed object passed as the 'ptr' argument in the event of
01297  * internal allocation in this method failing because of memory
01298  * exhaustion (in that event, Cgu::SharedHandleError will be thrown).
01299  * @exception Cgu::SharedHandleError This method might throw
01300  * Cgu::SharedHandleError if memory is exhausted and the system would
01301  * otherwise throw std::bad_alloc in that case.  Note that if such an
01302  * exception is thrown then this method will do nothing (it is
01303  * strongly exception safe and will continue to manage the object it
01304  * was managing prior to the call), and it will not attempt to delete
01305  * the new managed object passed to it (if any).  Access to the object
01306  * passed to the 'ptr' argument can be obtained via the thrown
01307  * Cgu::SharedHandleError object.
01308  * @note 1. A SharedLockHandle object protects its reference count but
01309  * not the managed object or its other internals.  The reset() method
01310  * should not be called by one thread in respect of a particular
01311  * SharedLockHandle object while another thread may be operating on,
01312  * copying or dereferencing the same instance of SharedLockHandle.  It
01313  * is thread-safe as against another instance of SharedLockHandle
01314  * managing the same object.
01315  * @note 2. On systems with over-commit/lazy-commit combined with
01316  * virtual memory (swap), it is rarely useful to check for memory
01317  * exhaustion, so in those cases this version of the reset() method
01318  * will not be useful.
01319  * @note 3. If the library has been installed using the
01320  * --with-glib-memory-slices-no-compat configuration option this
01321  * version of the reset() method will also not be useful: instead glib
01322  * will terminate the program if it is unable to obtain memory from
01323  * the operating system.
01324  * @note 4. By default, glib atomic functions are used to provide
01325  * thread-safe manipulation of the reference count.  However, a
01326  * library user can define the symbol CGU_SHARED_LOCK_HANDLE_USE_MUTEX
01327  * before shared_handle.h is parsed so as to use mutexes instead,
01328  * which might be useful for some debugging purposes.  Were she to do
01329  * so, Cgu::SharedHandleError might be thrown by this method if
01330  * initialization of the mutex fails (even if the
01331  * --with-glib-memory-slices-no-compat configuration option is
01332  * chosen), but it is usually not worth checking for such mutex
01333  * initialization failure.
01334  */
01335   void reset(T ptr, Cgu::SharedHandleAllocFail::Leave tag) {
01336     SharedLockHandle tmp(ptr, tag);
01337     std::swap(ref_items, tmp.ref_items);
01338   }
01339 
01340  /**
01341   * The copy constructor does not throw.
01342   * @param sh_hand The handle to be copied.
01343   */
01344   SharedLockHandle(const SharedLockHandle& sh_hand) {
01345     ref_items = sh_hand.ref_items;
01346     reference();
01347   }
01348 
01349  /**
01350   * The move constructor does not throw.  It has move semantics.
01351   * @param sh_hand The handle to be moved.
01352   */
01353   SharedLockHandle(SharedLockHandle&& sh_hand) {
01354     ref_items = sh_hand.ref_items;
01355 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
01356     sh_hand.ref_items.mutex_p = 0;  // make sure the value is valid as we may assign it
01357 #endif
01358     sh_hand.ref_items.ref_count_p = 0;
01359     sh_hand.ref_items.obj = 0;
01360   }
01361 
01362  /**
01363   * This method (and so copy or move assignment) does not throw unless
01364   * the destructor of a managed object throws.
01365   * @param sh_hand the assignor.
01366   * @return The SharedLockHandle object after assignment.
01367   */
01368   // having a value type as the argument, rather than reference to const
01369   // and then initialising a tmp object, gives the compiler more scope
01370   // for optimisation
01371   SharedLockHandle& operator=(SharedLockHandle sh_hand) {
01372     std::swap(ref_items, sh_hand.ref_items);
01373     return *this;
01374   }
01375 
01376  /**
01377   * This method does not throw.
01378   * @return A pointer to the handled object (or NULL if none is
01379   * handled).
01380   */
01381   T get() const {return ref_items.obj;}
01382 
01383  /**
01384   * This method does not throw.
01385   * @return A pointer to the handled object (or NULL if none is
01386   * handled).
01387   */
01388   operator T() const {return ref_items.obj;}
01389 
01390  /**
01391   * This method does not throw.
01392   * @return The number of SharedLockHandle objects referencing the
01393   * managed object (or 0 if none is managed by this SharedLockHandle).
01394   * @note The return value may not be valid if another thread has
01395   * changed the reference count before the value returned by this
01396   * method is acted on.  It is provided as a utility, but may not be
01397   * meaningful, depending on the intended usage.
01398   */
01399   unsigned int get_refcount() const {
01400     if (!ref_items.ref_count_p) return 0;
01401 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
01402     Thread::Mutex::Lock lock(*ref_items.mutex_p);
01403     return *ref_items.ref_count_p;
01404 #else
01405     return g_atomic_int_get(ref_items.ref_count_p);
01406 #endif
01407   }
01408 
01409  /**
01410   * The destructor does not throw unless the destructor of a handled
01411   * object throws - that should never happen.
01412   */
01413   ~SharedLockHandle() {unreference();}
01414 };
01415 
01416 #if defined(CGU_USE_SMART_PTR_COMPARISON) || defined(DOXYGEN_PARSING)
01417 
01418 // we can use built-in operator == when comparing pointers referencing
01419 // different objects of the same type
01420 /**
01421  * @ingroup handles
01422  *
01423  * This comparison operator does not throw.  It compares the addresses
01424  * of the managed objects.
01425  *
01426  * Since 2.0.0-rc2
01427  */
01428 template <class T, class Dealloc>
01429 bool operator==(const SharedHandle<T, Dealloc>& s1, const SharedHandle<T, Dealloc>& s2) {
01430   return (s1.get() == s2.get());
01431 }
01432 
01433 /**
01434  * @ingroup handles
01435  *
01436  * This comparison operator does not throw.  It compares the addresses
01437  * of the managed objects.
01438  *
01439  * Since 2.0.0-rc2
01440  */
01441 template <class T, class Dealloc>
01442 bool operator!=(const SharedHandle<T, Dealloc>& s1, const SharedHandle<T, Dealloc>& s2) {
01443   return !(s1 == s2);
01444 }
01445 
01446 // we must use std::less rather than the < built-in operator for
01447 // pointers to objects not within the same array or object: "For
01448 // templates greater, less, greater_equal, and less_equal, the
01449 // specializations for any pointer type yield a total order, even if
01450 // the built-in operators <, >, <=, >= do not." (para 20.3.3/8).
01451 /**
01452  * @ingroup handles
01453  *
01454  * This comparison operator does not throw.  It compares the addresses
01455  * of the managed objects.
01456  *
01457  * Since 2.0.0-rc2
01458  */
01459 template <class T, class Dealloc>
01460 bool operator<(const SharedHandle<T, Dealloc>& s1, const SharedHandle<T, Dealloc>& s2) {
01461   return std::less<T>()(s1.get(), s2.get());
01462 }
01463 
01464 /**
01465  * @ingroup handles
01466  *
01467  * This comparison operator does not throw.  It compares the addresses
01468  * of the managed objects.
01469  *
01470  * Since 2.0.0-rc2
01471  */
01472 template <class T, class Dealloc>
01473 bool operator==(const SharedLockHandle<T, Dealloc>& s1, const SharedLockHandle<T, Dealloc>& s2) {
01474   return (s1.get() == s2.get());
01475 }
01476 
01477 /**
01478  * @ingroup handles
01479  *
01480  * This comparison operator does not throw.  It compares the addresses
01481  * of the managed objects.
01482  *
01483  * Since 2.0.0-rc2
01484  */
01485 template <class T, class Dealloc>
01486 bool operator!=(const SharedLockHandle<T, Dealloc>& s1, const SharedLockHandle<T, Dealloc>& s2) {
01487   return !(s1 == s2);
01488 }
01489 
01490 /**
01491  * @ingroup handles
01492  *
01493  * This comparison operator does not throw.  It compares the addresses
01494  * of the managed objects.
01495  *
01496  * Since 2.0.0-rc2
01497  */
01498 template <class T, class Dealloc>
01499 bool operator<(const SharedLockHandle<T, Dealloc>& s1, const SharedLockHandle<T, Dealloc>& s2) {
01500   return std::less<T>()(s1.get(), s2.get());
01501 }
01502 
01503 #endif // CGU_USE_SMART_PTR_COMPARISON
01504 
01505 } // namespace Cgu
01506 
01507 // doxygen produces long filenames that tar can't handle:
01508 // we have generic documentation for std::hash specialisations
01509 // in doxygen.main.in
01510 #if defined(CGU_USE_SMART_PTR_COMPARISON) && !defined(DOXYGEN_PARSING)
01511 /* These structs allow SharedHandle and SharedLockHandle objects to be
01512    keys in unordered associative containers */
01513 namespace std {
01514 template <class T, class Dealloc>
01515 struct hash<Cgu::SharedHandle<T, Dealloc>> {
01516   typedef std::size_t result_type;
01517   typedef Cgu::SharedHandle<T, Dealloc> argument_type;
01518   result_type operator()(const argument_type& s) const {
01519     // this is fine: std::hash structs do not normally contain data and
01520     // std::hash<T*> certainly won't, so we don't have overhead constructing
01521     // std::hash<T*> on the fly
01522     return std::hash<T>()(s.get());
01523   }
01524 };
01525 template <class T, class Dealloc>
01526 struct hash<Cgu::SharedLockHandle<T, Dealloc>> {
01527   typedef std::size_t result_type;
01528   typedef Cgu::SharedLockHandle<T, Dealloc> argument_type;
01529   result_type operator()(const argument_type& s) const {
01530     // this is fine: std::hash structs do not normally contain data and
01531     // std::hash<T*> certainly won't, so we don't have overhead constructing
01532     // std::hash<T*> on the fly
01533     return std::hash<T>()(s.get());
01534   }
01535 };
01536 } // namespace std
01537 #endif // CGU_USE_SMART_PTR_COMPARISON
01538 
01539 #endif