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