c++-gtk-utils
shared_handle.h
Go to the documentation of this file.
1 /* Copyright (C) 2004 to 2012 Chris Vine
2 
3 The library comprised in this file or of which this file is part is
4 distributed by Chris Vine under the GNU Lesser General Public
5 License as follows:
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public License
9  as published by the Free Software Foundation; either version 2.1 of
10  the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License, version 2.1, for more details.
16 
17  You should have received a copy of the GNU Lesser General Public
18  License, version 2.1, along with this library (see the file LGPL.TXT
19  which came with this source code package in the c++-gtk-utils
20  sub-directory); if not, write to the Free Software Foundation, Inc.,
21  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 
23 However, it is not intended that the object code of a program whose
24 source code instantiates a template from this file or uses macros or
25 inline functions (of any length) should by reason only of that
26 instantiation or use be subject to the restrictions of use in the GNU
27 Lesser General Public License. With that in mind, the words "and
28 macros, inline functions and instantiations of templates (of any
29 length)" shall be treated as substituted for the words "and small
30 macros and small inline functions (ten lines or less in length)" in
31 the fourth paragraph of section 5 of that licence. This does not
32 affect any other reason why object code may be subject to the
33 restrictions in that licence (nor for the avoidance of doubt does it
34 affect the application of section 2 of that licence to modifications
35 of the source code in this file).
36 
37 */
38 
39 #ifndef CGU_SHARED_HANDLE_H
40 #define CGU_SHARED_HANDLE_H
41 
42 // define this if, instead of GLIB atomic funcions/memory barriers,
43 // you want to use a (slower) mutex to lock the reference count in the
44 // SharedLockHandle class (however, if wanted, this is best left for
45 // definition in the user code)
46 /* #define CGU_SHARED_LOCK_HANDLE_USE_MUTEX 1 */
47 
48 #include <exception>
49 #include <new>
50 #include <functional> // for std::less and std::hash<T*>
51 #include <utility> // for std::swap
52 #include <cstddef> // for std::size_t
53 #include <cstdlib>
54 
55 #include <glib.h>
56 
57 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
58 #include <c++-gtk-utils/mutex.h>
59 #endif
60 
62 
63 /**
64  * @addtogroup handles handles and smart pointers
65  */
66 
67 namespace Cgu {
68 
69 /**
70  * @class SharedHandle shared_handle.h c++-gtk-utils/shared_handle.h
71  * @brief This is a generic class for managing the lifetime of objects
72  * allocated on freestore.
73  * @ingroup handles
74  * @sa SharedLockHandle
75  * @sa ScopedHandle
76  * @sa SharedHandleError
77  * @sa GcharSharedHandle
78  * @sa GerrorSharedHandle
79  * @sa StandardArrayDelete CFree GFree GerrorFree GSliceFree GSliceFreeSize GSliceDestroy
80  *
81  * The SharedHandle class is similar to the SharedPtr class (it keeps
82  * a reference count and deletes the handled object when the count
83  * reaches 0), but it does not have pointer semantics. Accordingly,
84  * it can be used to manage the memory of arrays and other objects
85  * allocated on the heap.
86  *
87  * Because it is useful with arrays, by default it deallocates memory
88  * using C++ delete[]. However, if a SharedHandle object is passed a
89  * function object type as a second template argument when
90  * instantiated, it will use that function object to delete memory.
91  * This enables it to handle the memory of any object, such as objects
92  * to be deleted using std::free() or Glib's g_free(), g_list_free()
93  * or g_slice_free(). Instances (such as @ref GcharScopedHandleAnchor
94  * "GcharScopedHandle", @ref GcharSharedHandleAnchor
95  * "GcharSharedHandle", @ref GerrorSharedHandleAnchor
96  * "GerrorSharedHandle" and @ref GerrorScopedHandleAnchor
97  * "GerrorScopedHandle") typdef'ed for particular deleters can
98  * conveniently manage objects of any kind.
99  *
100  * To reflect the fact that it is just a handle for a pointer, it has
101  * different instantiation semantics from a SharedPtr object. A
102  * SharedPtr object is instantiated using this syntax:
103  *
104  * @code SharedPtr<ObjType> sh_ptr(new ObjType); @endcode
105  *
106  * A SharedHandle is instantiated using this syntax (note that the
107  * instantiated handle is for type T* and not T):
108  *
109  * @code SharedHandle<ObjType*> sh_handle(new ObjType[n]); @endcode
110  *
111  *
112  * Apart from the operatorT() type conversion operator (which returns
113  * the underlying pointer), the only other method to obtain the
114  * underlying pointer is the get() method. If the object referenced
115  * is an array allocated on the heap, to use indexing you could either
116  * do this:
117  *
118  * @code
119  * using namespace Cgu;
120  * SharedHandle<char*> handle(new char[10]);
121  * handle.get()[0] = 'a';
122  * std::cout << handle.get()[0] << std::endl;
123  * @endcode
124  *
125  * or this:
126  *
127  * @code
128  * using namespace Cgu;
129  * SharedHandle<char*> handle(new char[10]);
130  * handle[0] = 'a';
131  * std::cout << handle[0] << std::endl;
132  * @endcode
133  *
134  * There is also a SharedLockHandle class, which has a thread-safe
135  * reference count, and a ScopedHandle class, which deletes its object
136  * as soon as it goes out of scope. A ScopedHandle class can be
137  * viewed as a SharedHandle which cannot be assigned to or used as the
138  * argument to a copy constructor and therefore which cannot have a
139  * reference count of more than 1. It is used where, if you wanted
140  * pointer semantics, you might use a const std::auto_ptr<>.
141  *
142  * SharedHandle objects can be instantiated for pointers to constant
143  * objects (such as SharedHandle<const char*>), provided the deleter
144  * functor will take such pointers.
145  *
146  * This library provides StandardArrayDelete, CFree, GFree,
147  * GerrorFree, GSliceFree, GSliceFreeSize and GSliceDestroy deleter
148  * functors, which can be used as the second template parameter of the
149  * SharedHandle class. As mentioned above, StandardArrayDelete is the
150  * default, and some typedef'ed instances of SharedHandle for gchar
151  * (with the GFree deleter) and for GError (with the GerrorFree
152  * deleter) are provided.
153  *
154  * @b Comparison @b with @b std::shared_ptr
155  *
156  * Although the semantics of std::shared_ptr in C++11 are not
157  * particularly suited to managing either arrays or C objects with
158  * accessor functions (such as in glib), most of the things that can
159  * be done by this class can be done by using std::shared_ptr with a
160  * specialised deleter. However, this class is retained in the
161  * c++-gtk-utils library not only to retain compatibility with series
162  * 1.2 of the library, but also to cater for some cases not met (or
163  * not so easily met) by std::shared_ptr:
164  *
165  * (i) The Cgu::SharedHandle class takes its deleter as a template
166  * parameter, which means that typedefs can be used to enable handles
167  * for particular deleters to be easily created (and as mentioned,
168  * this library provides a number of pre-formed deleter functors and
169  * typedefs for them). With std::shared_ptr, custom deleters must be
170  * passed to the shared_ptr constructor on every occasion a shared_ptr
171  * is constructed to manage a new object (and they cannot be templated
172  * as a typedef).
173  *
174  * (ii) Glib memory slices provide an efficient small object allocator
175  * (they are likely to be significantly more efficient than global
176  * operator new()/new[](), which generally hand off to malloc(), and
177  * whilst malloc() is good for large block allocations it is generally
178  * poor as a small object allocator). Internal Cgu::SharedHandle
179  * allocation using glib memory slices can be achieved by compiling
180  * the library with the --with-glib-memory-slices-no-compat
181  * configuration option.
182  *
183  * (iii) If glib memory slices are not used (which do not throw),
184  * constructing a shared pointer for a new managed object (or calling
185  * reset() for a new managed object) might throw if internal
186  * allocation fails. Although by default the Cgu::SharedHandle
187  * implementation will delete the new managed object in such a case,
188  * it also provides an alternative constructor and reset() method
189  * which instead enable the new object to be accessed via the thrown
190  * exception object so that user code can decide what to do;
191  * std::shared_ptr deletes the new object in every case.
192  *
193  * (iv) A user can explicitly state whether the shared handle object
194  * is to have atomic increment and decrement-and-test with respect to
195  * the reference count so that the reference count is thread safe
196  * ('no' in the case of Cgu::SharedHandle, and 'yes' in the case of
197  * Cgu::SharedLockHandle). Using atomic functions is unnecessary if
198  * the managed object concerned is only addressed in one thread (and
199  * might cause unwanted cache flushing in certain circumstances).
200  * std::shared_ptr will generally always use atomic functions with
201  * respect to its reference count in a multi-threaded program.
202  *
203  * In favour of std::shared_ptr, it has an associated std::weak_ptr
204  * class, which Cgu::SharedHandle does not (there is a
205  * Cgu::GobjWeakHandle class, but that is cognate with Cgu::GobjHandle
206  * and is only usable with GObjects).
207  *
208  * If the library is compiled with the
209  * --with-glib-memory-slices-no-compat configuration option, as
210  * mentioned Cgu::SharedHandle constructs its reference counting
211  * internals using glib memory slices. Although it is safe in a
212  * multi-threaded program if glib < 2.32 is installed to construct a
213  * static SharedHandle object in global namespace (that is, prior to
214  * g_thread_init() being called) by means of the default constructor
215  * and/or a pointer argument of NULL, it is not safe if constructed
216  * with a non-NULL pointer value. If glib >= 2.32 is installed,
217  * global objects with memory slices are safe in all
218  * circumstances. (Having said that, it would be highly unusual to
219  * have global SharedHandle objects.)
220  */
221 
222 /********************* here are some deleter classes *******************/
223 
224 /**
225  * @class StandardArrayDelete shared_handle.h c++-gtk-utils/shared_handle.h
226  * @brief A deleter functor for use as the second (Dealloc) template
227  * parameter of the SharedHandle, SharedLockHandle or ScopedHandle
228  * template classes, which calls the C++ delete[] expression.
229  * @ingroup handles
230  * @details This functor enables those classes to manage arrays
231  * created with the new expression. It is the default type of the
232  * second template paramenter of those classes.
233  */
234 template <class T> class StandardArrayDelete {
235 public:
236  void operator()(T obj) {
237  delete[] obj;
238  }
239 };
240 
241 /**
242  * @class CFree shared_handle.h c++-gtk-utils/shared_handle.h
243  * @brief A deleter functor for use as the second (Dealloc) template
244  * parameter of the SharedHandle, SharedLockHandle or ScopedHandle
245  * template classes, which calls std::free.
246  * @ingroup handles
247  * @details This functor enables those classes to manage memory
248  * allocated with std::malloc(), std::calloc() and std::realloc().
249  */
250 class CFree {
251 public:
252  void operator()(const void* obj) {
253  std::free(const_cast<void*>(obj));
254  }
255 };
256 
257 /**
258  * @class GFree shared_handle.h c++-gtk-utils/shared_handle.h
259  * @brief A deleter functor for use as the second (Dealloc) template
260  * parameter of the SharedHandle, SharedLockHandle or ScopedHandle
261  * template classes, which calls glib's g_free().
262  * @ingroup handles
263  * @details This functor enables those classes to manage memory
264  * allocated by glib or gtk+ functions which requires to be freed with
265  * g_free(). It is used in the typedefs @ref GcharSharedHandleAnchor
266  * "GcharSharedHandle" and @ref GcharScopedHandleAnchor
267  * "GcharScopedHandle".
268  */
269 class GFree {
270 public:
271  void operator()(const void* obj) {
272  g_free(const_cast<void*>(obj));
273  }
274 };
275 
276 /**
277  * @class GSliceFree shared_handle.h c++-gtk-utils/shared_handle.h
278  * @brief A deleter functor for use as the second (Dealloc) template
279  * parameter of the SharedHandle, SharedLockHandle or ScopedHandle
280  * template classes, which calls glib's g_slice_free1().
281  * @ingroup handles
282  *
283  * @details This functor enables those classes to manage a memory
284  * block allocated using glib memory slices. The managed memory block
285  * to be deleted by the GSliceFree functor must have the same size as
286  * the size of the object for which the functor is instantiated by
287  * pointer, as for example as allocated with the g_slice_new,
288  * g_slice_new0 or g_slice_dup macros (in other words, the GSliceFree
289  * template parameter must match the argument passed to those macros):
290  * see the example below. Use GSliceFreeSize where it is necessary or
291  * more convenient to have the size of the block to be freed as the
292  * template parameter. Use GSliceDestroy where the memory holds a C++
293  * object constructed in the memory by the global placement new
294  * expression.
295  *
296  * The type of the template argument for the functor is a pointer to
297  * the managed type: it is the same as the first template argument of
298  * the relevant SharedHandle, SharedLockHandle or ScopedHandle object.
299  * For example:
300  *
301  * @code
302  * using namespace Cgu;
303  * SharedHandle<MyStruct*, GSliceFree<MyStruct*> > h(g_slice_new(MyStruct));
304  * ...
305  * @endcode
306  *
307  * The availability of this functor is not dependent on the library
308  * having been installed with the --with-glib-memory-slices-compat or
309  * --with-glib-memory-slices-no-compat configuration option (see @ref
310  * Memory for further details of those options).
311  */
312 template <class T> class GSliceFree {
313 public:
314  void operator()(T obj) {
315  g_slice_free1(sizeof(*obj), (void*)obj);
316  }
317 };
318 
319 /**
320  * @class GSliceDestroy shared_handle.h c++-gtk-utils/shared_handle.h
321  * @brief A deleter functor for use as the second (Dealloc) template
322  * parameter of the SharedHandle, SharedLockHandle or ScopedHandle
323  * template classes, which calls glib's g_slice_free1(), but before
324  * doing so also explicitly calls the destructor of a C++ object
325  * constructed in the memory.
326  * @ingroup handles
327  *
328  * @details The managed memory block to be deleted by the
329  * GSliceDestroy functor must have the same size as the size of the
330  * object for which the functor is instantiated by pointer, as for
331  * example as allocated with the g_slice_new or g_slice_new0 macros
332  * (in other words, the GSliceDestroy template parameter must match
333  * the argument passed to those macros), and the memory block must
334  * have had that object constructed in it with the global placement
335  * new expression: see the example below. Sometimes it is more
336  * convenient to implement C++ objects in glib memory slices that way,
337  * rather than to have custom new and delete member operators of the
338  * classes concerned which use glib's g_slice_*(). However, a
339  * SharedHandle class with a GSliceDestroy deleter is not as easy to
340  * use as the SharedPtr class, as SharedHandle has no operator*() nor
341  * operator->() method (the get() method would have to be used to
342  * obtain the underlying pointer).
343  *
344  * One consequence of the static sizing (and so typing) of memory
345  * slices is that a GSliceDestroy object instantiated for the
346  * management of a particular class must not be used by a
347  * SharedHandle, SharedLockHandle or ScopedHandle object which
348  * attempts to manage a class derived from it. This comes back to the
349  * point that the GSliceDestroy template parameter must match the
350  * argument passed to the g_slice_new or g_slice_new0 macros.
351  *
352  * The type of the template argument for the functor is a pointer to
353  * the managed type: it is the same as the first template argument of
354  * the relevant SharedHandle, SharedLockHandle or ScopedHandle object.
355  * For example, to construct a SharedHandle managing an object of type
356  * MyClass to be constructed in a glib memory slice in an exception
357  * safe way:
358  *
359  * @code
360  * using namespace Cgu;
361  * SharedHandle<MyClass*, GSliceDestroy<MyClass*> > h; // won't throw
362  * { // scope block for p variable
363  * MyClass* p = g_slice_new(MyClass);
364  * try {new(p) MyClass;} // MyClass constructor might throw
365  * catch(...) {
366  * g_slice_free(MyClass, p);
367  * throw;
368  * }
369  * h.reset(p); // might throw but if so cleans up
370  * }
371  * ...
372  * @endcode
373  *
374  * The availability of this functor is not dependent on the library
375  * having been installed with the --with-glib-memory-slices-compat or
376  * --with-glib-memory-slices-no-compat configuration option (see @ref
377  * Memory for further details of those options).
378  */
379 template <class T> class GSliceDestroy {
380  template <class U> void destroy(U& obj) {obj.~U();}
381 public:
382  void operator()(T obj) {
383  destroy(*obj);
384  g_slice_free1(sizeof(*obj), (void*)obj);
385  }
386 };
387 
388 /**
389  * @class GSliceFreeSize shared_handle.h c++-gtk-utils/shared_handle.h
390  * @brief A deleter functor for use as the second (Dealloc) template
391  * parameter of the SharedHandle, SharedLockHandle or ScopedHandle
392  * template classes, which calls glib's g_slice_free1().
393  * @ingroup handles
394  *
395  * @details This functor enables those classes to manage memory
396  * allocated with g_slice_alloc(), g_slice_alloc0() or g_slice_copy().
397  * It is an alternative to using GSliceFree where, instead of the
398  * template parameter being a pointer to a particular managed type,
399  * the size of the memory block to be freed is passed, so enabling it
400  * to be more conveniently used to free memory containing arrays of
401  * built-in types or of PODSs. Use GSliceDestroy where the memory
402  * holds a C++ object constructed in the memory by the global
403  * placement new expression.
404  *
405  * The type of the template argument for the functor is an integer
406  * type (gsize) and is the size of the block to be managed. For
407  * example:
408  *
409  * @code
410  * using namespace Cgu;
411  * SharedHandle<char*, GSliceFreeSize<10> > h(static_cast<char*>(g_slice_alloc(10)));
412  * ...
413  * @endcode
414  *
415  * The availability of this functor is not dependent on the library
416  * having been installed with the --with-glib-memory-slices-compat or
417  * --with-glib-memory-slices-no-compat configuration option (see @ref
418  * Memory for further details of those options).
419  */
420 template <gsize block_size> class GSliceFreeSize {
421 public:
422  void operator()(const void* obj) {
423  g_slice_free1(block_size, const_cast<void*>(obj));
424  }
425 };
426 
427 /*
428  * we could provide a functor class for
429  * g_slice_free_chain_with_offset() such as:
430  *
431  * template <class T, gsize offset> class GSliceFreeChain {
432  * public:
433  * void operator()(T obj) {
434  * g_slice_free_chain_with_offset(sizeof(*obj), (void*)obj, offset);
435  * }
436  * };
437  *
438  * However, this is not going to be particularly useful because the
439  * G_STRUCT_OFFSET macro and/or C's offsetof macro, needed to provide
440  * the value for the offset parameter, do not work for other than
441  * PODSs. g_slice_free_chain_with_offset() is intended for internal
442  * implementations and in the event of a user wanting such memory
443  * management it is best achieved by having custom new[] and delete[]
444  * member operators of the class concerned which use glib's
445  * g_slice_*() directly.
446  */
447 
448 /********************* define some typedefs for Glib ******************/
449 
450 template <class T, class Dealloc> class SharedHandle;
451 template <class T, class Dealloc> class ScopedHandle;
452 
453 /**
454  * @typedef GcharSharedHandle.
455  * @brief A handle comprising a typed instance of the SharedHandle
456  * class for gchar* arrays and strings
457  * @anchor GcharSharedHandleAnchor
458  * @ingroup handles
459  * \#include <c++-gtk-utils/shared_handle.h>
460  */
462 
463 /**
464  * @typedef GcharScopedHandle.
465  * @brief A handle comprising a typed instance of the ScopedHandle
466  * class for gchar* arrays and strings
467  * @anchor GcharScopedHandleAnchor
468  * @ingroup handles
469  * \#include <c++-gtk-utils/shared_handle.h>
470 */
472 
473 
474 /******************* now the handle class definitions *****************/
475 
476 /**
477  * @class SharedHandleError shared_handle.h c++-gtk-utils/shared_handle.h
478  * @brief This is an exception struct thrown as an alternative to
479  * deleting a managed object when internal memory allocation for
480  * SharedHandle or SharedLockHandle fails in their reset() method or
481  * in their constructor which takes a pointer.
482  * @sa SharedHandle SharedLockHandle SharedHandleAllocFail
483  * @ingroup handles
484  *
485  * This is an exception struct thrown as an alternative to deleting a
486  * managed object when SharedHandle<T>::SharedHandle(T),
487  * SharedLockHandle<T>::SharedLockHandle(T), SharedHandle<T>::reset(T)
488  * or SharedLockHandle<T>::reset(T) would otherwise throw
489  * std::bad_alloc. To make those methods do that,
490  * Cgu::SharedHandleAllocFail::leave is passed as their second
491  * argument.
492  *
493  * If the exception is thrown, the struct has a member 'obj' of type
494  * T, which is a pointer to the object or array originally passed to
495  * those methods, so the user can deal with it appropriately. This
496  * enables the result of the new expression to be passed directly as
497  * the argument to those methods without giving rise to a resource
498  * leak, as in:
499  *
500  * @code
501  * using namespace Cgu;
502  * SharedHandle<T*> s; // doesn't throw
503  * try {
504  * s.reset(new T[2], SharedHandleAllocFail::leave); // both T allocation and reset() might throw
505  * }
506  * catch (std::bad_alloc&) {
507  * ...
508  * }
509  * catch (SharedHandleError<T*>& e) {
510  * e.obj[0].do_something();
511  * e.obj[1].do_something();
512  * ...
513  * }
514  * ...
515  * @endcode
516  *
517  * As above, a catch block will need to deal with std::bad_alloc (if
518  * the call to the new expression when creating the T object fails)
519  * as well as SharedHandleError (if the call to the new expression in
520  * the reset() method fails after a valid T object has been
521  * constructed).
522  */
523 
524 template <class T> struct SharedHandleError: public std::exception {
525  T obj;
526  virtual const char* what() const throw() {return "SharedHandleError\n";}
527  SharedHandleError(T p): obj(p) {}
528 };
529 
530 /**
531  * enum Cgu::SharedHandleAllocFail::Leave
532  * The enumerator Cgu::SharedHandleAllocFail::leave is passed as the
533  * second argument of the reset() method of SharedHandle or
534  * SharedLockHandle in order to prevent the method deleting the object
535  * passed to it if reset() fails internally because of memory
536  * exhaustion.
537  * @ingroup handles
538  */
539 namespace SharedHandleAllocFail {
540  enum Leave {leave};
541 }
542 
543 template <class T, class Dealloc = StandardArrayDelete<T>> class SharedHandle {
544 
545  Dealloc deleter;
546 
547 #ifndef DOXYGEN_PARSING
548  struct RefItems {
549  unsigned int* ref_count_p;
550  T obj;
551  } ref_items;
552 #endif
553 
554  void unreference() {
555  if (!ref_items.ref_count_p) return;
556  --(*ref_items.ref_count_p);
557  if (*ref_items.ref_count_p == 0) {
558 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
559  g_slice_free(unsigned int, ref_items.ref_count_p);
560 #else
561  delete ref_items.ref_count_p;
562 #endif
563  deleter(ref_items.obj);
564  }
565  }
566 
567  void reference() {
568  if (!ref_items.ref_count_p) return;
569  ++(*ref_items.ref_count_p);
570  }
571 
572 public:
573 /**
574  * Constructor taking an unmanaged object.
575  * @param ptr The object which the SharedHandle is to manage (if
576  * any).
577  * @exception std::bad_alloc This constructor will not throw if the
578  * 'ptr' argument has a NULL value (the default), otherwise it might
579  * throw std::bad_alloc if memory is exhausted and the system throws
580  * in that case. If such an exception is thrown, this constructor is
581  * exception safe (it does not leak resources), but as well as
582  * cleaning itself up this constructor will also delete the managed
583  * object passed to it to avoid a memory leak. If such automatic
584  * deletion is not wanted in that case, use the version of this
585  * constructor taking a Cgu::SharedHandleAllocFail::Leave tag argument.
586  * @note std::bad_alloc will not be thrown if the library has been
587  * installed using the --with-glib-memory-slices-no-compat
588  * configuration option: instead glib will terminate the program if it
589  * is unable to obtain memory from the operating system.
590  */
591  explicit SharedHandle(T ptr = 0) {
592 
593  if ((ref_items.obj = ptr)) { // not NULL
594 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
595  ref_items.ref_count_p = g_slice_new(unsigned int);
596  *ref_items.ref_count_p = 1;
597 #else
598  try {
599  ref_items.ref_count_p = new unsigned int(1);
600  }
601  catch (...) {
602  deleter(ptr); // if allocating the int referenced by ref_items.ref_count_p
603  // has failed then delete the object to be referenced to
604  // avoid a memory leak
605  throw;
606  }
607 #endif
608  }
609  else ref_items.ref_count_p = 0;
610  }
611 
612 /**
613  * Constructor taking an unmanaged object.
614  * @param ptr The object which the SharedHandle is to manage
615  * @param tag Passing the tag emumerator
616  * Cgu::SharedHandleAllocFail::leave causes this constructor not to
617  * delete the new managed object passed as the 'ptr' argument in the
618  * event of internal allocation in this method failing because of
619  * memory exhaustion (in that event, Cgu::SharedHandleError will be
620  * thrown).
621  * @exception Cgu::SharedHandleError This constructor might throw
622  * Cgu::SharedHandleError if memory is exhausted and the system would
623  * otherwise throw std::bad_alloc in that case. This constructor is
624  * exception safe (it does not leak resources), and if such an
625  * exception is thrown it will clean itself up, but it will not
626  * attempt to delete the new managed object passed to it. Access to
627  * the object passed to the 'ptr' argument can be obtained via the
628  * thrown Cgu::SharedHandleError object.
629  * @note 1. On systems with over-commit/lazy-commit combined with
630  * virtual memory (swap), it is rarely useful to check for memory
631  * exhaustion, so in those cases this version of the constructor will
632  * not be useful.
633  * @note 2. If the library has been installed using the
634  * --with-glib-memory-slices-no-compat configuration option this
635  * version of the constructor will also not be useful: instead glib
636  * will terminate the program if it is unable to obtain memory from
637  * the operating system.
638  */
640 
641  if ((ref_items.obj = ptr)) { // not NULL
642 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
643  ref_items.ref_count_p = g_slice_new(unsigned int);
644  *ref_items.ref_count_p = 1;
645 #else
646  try {
647  ref_items.ref_count_p = new unsigned int(1);
648  }
649  catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly
650  throw SharedHandleError<T>(ptr);
651  }
652 #endif
653  }
654  else ref_items.ref_count_p = 0;
655  }
656 
657 /**
658  * Causes the SharedHandle to cease to manage its managed object (if
659  * any), deleting it if this is the last SharedHandle object managing
660  * it. If the argument passed is not NULL, the SharedHandle object
661  * will manage the new object passed (which must not be managed by any
662  * other SharedHandle object). This method is exception safe, but see
663  * the comments below on std::bad_alloc.
664  * @param ptr NULL (the default), or a new unmanaged object to manage.
665  * @exception std::bad_alloc This method will not throw if the 'ptr'
666  * argument has a NULL value (the default) and the destructor of a
667  * managed object does not throw, otherwise it might throw
668  * std::bad_alloc if memory is exhausted and the system throws in that
669  * case. Note that if such an exception is thrown then this method
670  * will do nothing (it is strongly exception safe and will continue to
671  * manage the object it was managing prior to the call), except that
672  * it will delete the new managed object passed to it to avoid a
673  * memory leak. If such automatic deletion in the event of such an
674  * exception is not wanted, use the reset() method taking a
675  * Cgu::SharedHandleAllocFail::Leave tag type as its second argument.
676  * @note std::bad_alloc will not be thrown if the library has been
677  * installed using the --with-glib-memory-slices-no-compat
678  * configuration option: instead glib will terminate the program if it
679  * is unable to obtain memory from the operating system.
680  */
681  void reset(T ptr = 0) {
682  SharedHandle tmp(ptr);
683  std::swap(ref_items, tmp.ref_items);
684  }
685 
686 /**
687  * Causes the SharedHandle to cease to manage its managed object (if
688  * any), deleting it if this is the last SharedHandle object managing
689  * it. The SharedHandle object will manage the new object passed
690  * (which must not be managed by any other SharedHandle object). This
691  * method is exception safe, but see the comments below on
692  * Cgu::SharedHandleError.
693  * @param ptr A new unmanaged object to manage (if no new object is to
694  * be managed, use the version of reset() taking a default value of
695  * NULL).
696  * @param tag Passing the tag emumerator
697  * Cgu::SharedHandleAllocFail::leave causes this method not to delete
698  * the new managed object passed as the 'ptr' argument in the event of
699  * internal allocation in this method failing because of memory
700  * exhaustion (in that event, Cgu::SharedHandleError will be thrown).
701  * @exception Cgu::SharedHandleError This method might throw
702  * Cgu::SharedHandleError if memory is exhausted and the system would
703  * otherwise throw std::bad_alloc in that case. Note that if such an
704  * exception is thrown then this method will do nothing (it is
705  * strongly exception safe and will continue to manage the object it
706  * was managing prior to the call), and it will not attempt to delete
707  * the new managed object passed to it. Access to the object passed
708  * to the 'ptr' argument can be obtained via the thrown
709  * Cgu::SharedHandleError object.
710  * @note 1. On systems with over-commit/lazy-commit combined with
711  * virtual memory (swap), it is rarely useful to check for memory
712  * exhaustion, so in those cases this version of the reset() method
713  * will not be useful.
714  * @note 2. If the library has been installed using the
715  * --with-glib-memory-slices-no-compat configuration option this
716  * version of the reset() method will also not be useful: instead glib
717  * will terminate the program if it is unable to obtain memory from
718  * the operating system.
719  */
721  SharedHandle tmp(ptr, tag);
722  std::swap(ref_items, tmp.ref_items);
723  }
724 
725  /**
726  * The copy constructor does not throw.
727  * @param sh_hand The handle to be copied.
728  */
729  SharedHandle(const SharedHandle& sh_hand) {
730  ref_items = sh_hand.ref_items;
731  reference();
732  }
733 
734  /**
735  * The move constructor does not throw. It has move semantics.
736  * @param sh_hand The handle to be moved.
737  */
739  ref_items = sh_hand.ref_items;
740  sh_hand.ref_items.ref_count_p = 0;
741  sh_hand.ref_items.obj = 0;
742  }
743 
744  /**
745  * This method (and so copy or move assignment) does not throw unless
746  * the destructor of a managed object throws.
747  * @param sh_hand the assignor.
748  * @return The SharedHandle object after assignment.
749  */
750  // having a value type as the argument, rather than reference to const
751  // and then initialising a tmp object, gives the compiler more scope
752  // for optimisation, and also caters for r-values without a separate
753  // overload
755  std::swap(ref_items, sh_hand.ref_items);
756  return *this;
757  }
758 
759  /**
760  * This method does not throw.
761  * @return A pointer to the handled object (or NULL if none is
762  * handled).
763  */
764  T get() const {return ref_items.obj;}
765 
766  /**
767  * This method does not throw.
768  * @return A pointer to the handled object (or NULL if none is
769  * handled).
770  */
771  operator T() const {return ref_items.obj;}
772 
773  /**
774  * This method does not throw.
775  * @return The number of SharedHandle objects referencing the managed
776  * object (or 0 if none is managed by this SharedHandle).
777  */
778  unsigned int get_refcount() const {return (ref_items.ref_count_p) ? *ref_items.ref_count_p : 0;}
779 
780  /**
781  * The destructor does not throw unless the destructor of a handled
782  * object throws - that should never happen.
783  */
784  ~SharedHandle() {unreference();}
785 };
786 
787 /**
788  * @class ScopedHandle shared_handle.h c++-gtk-utils/shared_handle.h
789  * @brief This is a generic scoped class for managing the lifetime of objects
790  * allocated on freestore.
791  * @ingroup handles
792  * @sa SharedHandle SharedLockHandle SharedHandleError
793  * @sa StandardArrayDelete CFree GFree GerrorFree GSliceFree GSliceFreeSize GSliceDestroy
794  *
795  * This class deletes its object as soon as it goes out of scope. It
796  * can be viewed as a SharedHandle which cannot be assigned to or used
797  * as the argument to a copy constructor and therefore which cannot
798  * have a reference count of more than 1.
799  *
800  * ScopedHandle objects can be instantiated for pointers to constant
801  * objects (such as ScopedHandle<const char*>), provided the deleter
802  * functor will take such pointers.
803  *
804  * This library provides StandardArrayDelete, CFree, GFree,
805  * GerrorFree, GSliceFree, GSliceFreeSize and GSliceDestroy deleter
806  * functors, which can be used as the second template parameter of the
807  * ScopedHandle class. StandardArrayDelete is the default, and some
808  * typedef'ed instances of ScopedHandle for gchar (with the GFree
809  * deleter) and for GError (with the GerrorFree deleter) are provided:
810  * @ref GcharScopedHandleAnchor "GcharScopedHandle" and @ref
811  * GerrorScopedHandleAnchor "GerrorScopedHandle")
812  *
813  * @b Comparison @b with @b std::unique_ptr
814  *
815  * Although the semantics of std::unique_ptr in C++11 are not
816  * particularly suited to managing C objects with accessor functions
817  * (such as in glib), most of the things that can be done by this
818  * class can be done by using std::unique_ptr with a specialised
819  * deleter. However, this class is retained in the c++-gtk-utils
820  * library not only to retain compatibility with series 1.2 of the
821  * library, but also to cater for some cases not so easily met by
822  * std::unique_ptr:
823  *
824  * (i) The Cgu::ScopedHandle class takes its deleter as a template
825  * parameter, which means that typedefs can be used to enable handles
826  * for particular deleters to be easily created (and as mentioned,
827  * this library provides a number of pre-formed deleter functors and
828  * typedefs for them). With std::unique_ptr, custom deleters must be
829  * passed to the unique_ptr constructor on every occasion a unique_ptr
830  * is constructed to manage a new object (and they cannot be templated
831  * as a typedef).
832  *
833  * (ii) This class provides non-move enforcement without making a
834  * const instance of it. A const std::unique_ptr cannot be moved from
835  * or to, but then it cannot have release() or reset() called for it
836  * either.
837  */
838 
839 template <class T, class Dealloc = StandardArrayDelete<T>> class ScopedHandle {
840  Dealloc deleter;
841  T obj;
842 public:
843 /**
844  * This class cannot be copied. The copy constructor is deleted.
845  */
846  ScopedHandle(const ScopedHandle&) = delete;
847 
848 /**
849  * This class cannot be copied. The assignment operator is deleted.
850  */
851  ScopedHandle& operator=(const ScopedHandle&) = delete;
852 
853 /**
854  * The constructor does not throw.
855  * @param ptr The object which the ScopedHandle is to manage (if
856  * any).
857  *
858  * ScopedHandle objects can be instantiated for pointers to constant
859  * objects (such as SharedHandle<const char*>), provided the deleter
860  * functor will take such pointers.
861  */
862  explicit ScopedHandle(T ptr = 0): obj(ptr) {}
863 
864 /**
865  * Causes the ScopedHandle to delete its managed object (if any), and
866  * if the argument passed is not NULL, the ScopedHandle object will
867  * manage the new object passed (which must not be managed by any
868  * other ScopedHandle object). This method does not throw (assuming
869  * the destructor of a managed object does not throw).
870  * @param ptr NULL (the default), or a new unmanaged object to manage.
871  */
872  void reset(T ptr = 0) {
873  std::swap(obj, ptr);
874  if (ptr) deleter(ptr); // ptr now points to the original managed object
875  }
876 
877 /**
878  * Causes the ScopedHandle to cease to manage the handled object, but
879  * does not delete that object. This method does not throw.
880  * @return A pointer to the previously handled object (or NULL if none
881  * was handled).
882  */
883  T release() {T tmp = obj; obj = 0; return tmp;}
884 
885 /**
886  * This method does not throw.
887  * @return A pointer to the handled object (or NULL if none is
888  * handled).
889  */
890  T get() const {return obj;}
891 
892 /**
893  * This method does not throw.
894  * @return A pointer to the handled object (or NULL if none is
895  * handled).
896  */
897  operator T() const {return obj;}
898 
899 /**
900  * The destructor does not throw unless the destructor of a handled
901  * object throws - that should never happen.
902  */
903  ~ScopedHandle() {if (obj) deleter(obj);}
904 };
905 
906 
907 /**
908  * @class SharedLockHandle shared_handle.h c++-gtk-utils/shared_handle.h
909  * @brief This is a generic class for managing the lifetime of objects
910  * allocated on freestore, with a thread safe reference count..
911  * @ingroup handles
912  * @sa SharedHandle ScopedHandle SharedHandleError
913  * @sa StandardArrayDelete CFree GFree GerrorFree GSliceFree GSliceFreeSize GSliceDestroy
914  *
915  * Class SharedLockHandle is a version of the SharedHandle class which
916  * includes locking so that it can be accessed in multiple threads
917  * (although the word Lock is in the title, by default it uses glib
918  * atomic functions to access the reference count rather than a mutex,
919  * so the overhead should be very small). Note that only the
920  * reference count is protected, so this is thread safe in the sense
921  * in which a raw pointer is thread safe. A shared handle accessed in
922  * one thread referencing a particular object is thread safe as
923  * against another shared handle accessing the same object in a
924  * different thread. It is thus suitable for use in different Std C++
925  * containers which exist in different threads but which contain
926  * shared objects by reference. But:
927  *
928  * 1. If the referenced object is to be modified in one thread and
929  * read or modified in another thread an appropriate mutex for the
930  * referenced object is required (unless that referenced object
931  * does its own locking).
932  *
933  * 2. If the same instance of shared handle is to be modified in one
934  * thread (by assigning to the handle so that it references a
935  * different object, or by moving from it), and copied (assigned
936  * from or used as the argument of a copy constructor), accessed,
937  * destroyed or modified in another thread, a mutex for that
938  * instance of shared handle is required.
939  *
940  * 3. Objects referenced by shared handles which are objects for
941  * which POSIX provides no guarantees (in the main, those which
942  * are not built-in types), such as strings and similar
943  * containers, may not support concurrent reads in different
944  * threads. That depends on the library implementation concerned.
945  * If that is the case, a mutex for the referenced object will
946  * also be required when reading any given instance of such an
947  * object in more than one thread by dereferencing any shared
948  * handles referencing it (and indeed, when not using shared
949  * handles at all).
950  *
951  * SharedLockHandle objects can be instantiated for pointers to
952  * constant objects (such as SharedLockHandle<const char*>), provided
953  * the deleter functor will take such pointers.
954  *
955  * This library provides StandardArrayDelete, CFree, GFree,
956  * GerrorFree, GSliceFree, GSliceFreeSize and GSliceDestroy deleter
957  * functors, which can be used as the second template parameter of the
958  * SharedLockHandle class. StandardArrayDelete is the default.
959  *
960  * As mentioned, by default glib atomic functions are used to provide
961  * thread-safe manipulation of the reference count. However, a
962  * library user can define the symbol CGU_SHARED_LOCK_HANDLE_USE_MUTEX
963  * before shared_handle.h is parsed so as to use mutexes instead,
964  * which might be useful for some debugging purposes.
965  *
966  * @b Comparison @b with @b std::shared_ptr
967  *
968  * Although the semantics of std::shared_ptr in C++11 are not
969  * particularly suited to managing either arrays or C objects with
970  * accessor functions (such as in glib), most of the things that can
971  * be done by this class can be done by using std::shared_ptr with a
972  * specialised deleter. However, this class is retained in the
973  * c++-gtk-utils library not only to retain compatibility with series
974  * 1.2 of the library, but also to cater for some cases not met (or
975  * not so easily met) by std::shared_ptr:
976  *
977  * (i) The Cgu::SharedLockHandle class takes its deleter as a template
978  * parameter, which means that typedefs can be used to enable handles
979  * for particular deleters to be easily created (and as mentioned,
980  * this library provides a number of pre-formed deleter functors and
981  * typedefs for them). With std::shared_ptr, custom deleters must be
982  * passed to the shared_ptr constructor on every occasion a shared_ptr
983  * is constructed to manage a new object (and they cannot be templated
984  * as a typedef).
985  *
986  * (ii) Glib memory slices provide an efficient small object allocator
987  * (they are likely to be significantly more efficient than global
988  * operator new()/new[](), which generally hand off to malloc(), and
989  * whilst malloc() is good for large block allocations it is generally
990  * poor as a small object allocator). Internal Cgu::SharedLockHandle
991  * allocation using glib memory slices can be achieved by compiling
992  * the library with the --with-glib-memory-slices-no-compat
993  * configuration option.
994  *
995  * (iii) If glib memory slices are not used (which do not throw),
996  * constructing a shared pointer for a new managed object (or calling
997  * reset() for a new managed object) might throw if internal
998  * allocation fails. Although by default the Cgu::SharedLockHandle
999  * implementation will delete the new managed object in such a case,
1000  * it also provides an alternative constructor and reset() method
1001  * which instead enable the new object to be accessed via the thrown
1002  * exception object so that user code can decide what to do;
1003  * std::shared_ptr deletes the new object in every case.
1004  *
1005  * (iv) A user can explicitly state whether the shared handle object
1006  * is to have atomic increment and decrement-and-test with respect to
1007  * the reference count so that the reference count is thread safe
1008  * ('no' in the case of Cgu::SharedHandle, and 'yes' in the case of
1009  * Cgu::SharedLockHandle). Using atomic functions is unnecessary if
1010  * the managed object concerned is only addressed in one thread (and
1011  * might cause unwanted cache flushing in certain circumstances).
1012  * std::shared_ptr will generally always use atomic functions with
1013  * respect to its reference count in a multi-threaded program.
1014  *
1015  * In favour of std::shared_ptr, it has an associated std::weak_ptr
1016  * class, which Cgu::SharedLockHandle does not (there is a
1017  * Cgu::GobjWeakHandle class, but that is cognate with Cgu::GobjHandle
1018  * and is only usable with GObjects). In addition shared_ptr objects
1019  * have some atomic store, load and exchange functions provided for
1020  * them which enable concurrent modifications of the same instance of
1021  * shared_ptr in different threads to have defined results.
1022  *
1023  * If the library is compiled with the
1024  * --with-glib-memory-slices-no-compat configuration option, as
1025  * mentioned Cgu::SharedLockHandle constructs its reference counting
1026  * internals using glib memory slices. Although it is safe in a
1027  * multi-threaded program if glib < 2.32 is installed to construct a
1028  * static SharedLockHandle object in global namespace (that is, prior
1029  * to g_thread_init() being called) by means of the default
1030  * constructor and/or a pointer argument of NULL, it is not safe if
1031  * constructed with a non-NULL pointer value. If glib >= 2.32 is
1032  * installed, global objects with memory slices are safe in all
1033  * circumstances. (Having said that, it would be highly unusual to
1034  * have global SharedLockHandle objects.)
1035  */
1036 
1037 template <class T, class Dealloc = StandardArrayDelete<T>> class SharedLockHandle {
1038 
1039  Dealloc deleter;
1040 
1041 #ifndef DOXYGEN_PARSING
1042  struct RefItems {
1043 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1044  Thread::Mutex* mutex_p;
1045  unsigned int* ref_count_p;
1046 #else
1047  gint* ref_count_p;
1048 #endif
1049  T obj;
1050  } ref_items;
1051 #endif
1052 
1053  // SharedLockHandle<T, Dealloc>::unreference() does not throw exceptions
1054  // because Thread::Mutex::~Mutex(), Thread::Mutex::lock() and Thread::Mutex::unlock()
1055  // do not throw
1056  void unreference() {
1057  // we can (and should) check whether ref_items.ref_count_p is NULL without
1058  // a lock, because that member is specific to this SharedLockHandle object.
1059  // Only the integer pointed to by it is shared amongst SharedLockHandle
1060  // objects and requires locking
1061  if (!ref_items.ref_count_p) return;
1062 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1063  ref_items.mutex_p->lock();
1064  --(*ref_items.ref_count_p);
1065  if (*ref_items.ref_count_p == 0) {
1066 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
1067  g_slice_free(unsigned int, ref_items.ref_count_p);
1068 # else
1069  delete ref_items.ref_count_p;
1070 # endif
1071  ref_items.mutex_p->unlock();
1072  delete ref_items.mutex_p;
1073  deleter(ref_items.obj);
1074  }
1075  else ref_items.mutex_p->unlock();
1076 #else
1077  if (g_atomic_int_dec_and_test(ref_items.ref_count_p)) {
1078 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
1079  g_slice_free(gint, ref_items.ref_count_p);
1080 # else
1081  delete ref_items.ref_count_p;
1082 # endif
1083  deleter(ref_items.obj);
1084  }
1085 #endif
1086  }
1087 
1088  // SharedLockHandle<T, Dealloc>::reference() does not throw exceptions because
1089  // Thread::Mutex::Lock::Lock() and Thread::Mutex::Lock::~Lock() do not throw
1090  void reference() {
1091  // we can (and should) check whether ref_items.ref_count_p is NULL without
1092  // a lock, because that member is specific to this SharedLockHandle object.
1093  // Only the integer pointed to by it is shared amongst SharedLockHandle
1094  // objects and requires locking
1095  if (!ref_items.ref_count_p) return;
1096 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1097  Thread::Mutex::Lock lock(*ref_items.mutex_p);
1098  ++(*ref_items.ref_count_p);
1099 #else
1100  g_atomic_int_inc(ref_items.ref_count_p);
1101 #endif
1102  }
1103 
1104 public:
1105 /**
1106  * Constructor taking an unmanaged object.
1107  * @param ptr The object which the SharedLockHandle is to manage (if
1108  * any).
1109  * @exception std::bad_alloc This constructor will not throw if the
1110  * 'ptr' argument has a NULL value (the default), otherwise it might
1111  * throw std::bad_alloc if memory is exhausted and the system throws
1112  * in that case. If such an exception is thrown, this constructor is
1113  * exception safe (it does not leak resources), but as well as
1114  * cleaning itself up this constructor will also delete the managed
1115  * object passed to it to avoid a memory leak. If such automatic
1116  * deletion is not wanted in that case, use the version of this
1117  * constructor taking a Cgu::SharedHandleAllocFail::Leave tag
1118  * argument.
1119  * @note 1. std::bad_alloc will not be thrown if the library has been
1120  * installed using the --with-glib-memory-slices-no-compat
1121  * configuration option: instead glib will terminate the program if it
1122  * is unable to obtain memory from the operating system.
1123  * @note 2. By default, glib atomic functions are used to provide
1124  * thread-safe manipulation of the reference count. However, a
1125  * library user can define the symbol CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1126  * before shared_handle.h is parsed so as to use mutexes instead,
1127  * which might be useful for some debugging purposes. Were she to do
1128  * so, Cgu::Thread::MutexError might be thrown by this constructor if
1129  * initialization of the mutex fails, but it is usually not worth
1130  * checking for this.
1131  */
1132  explicit SharedLockHandle(T ptr = 0) {
1133 
1134  if ((ref_items.obj = ptr)) { // not NULL
1135 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1136  try {
1137  ref_items.mutex_p = new Thread::Mutex;
1138  }
1139  catch (...) {
1140  deleter(ptr); // if allocating the object referenced by ref_items.mutex_p
1141  // has failed then delete the object to be referenced to
1142  // avoid a memory leak
1143  throw;
1144  }
1145 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
1146  ref_items.ref_count_p = g_slice_new(unsigned int);
1147  *ref_items.ref_count_p = 1;
1148 # else
1149  try {
1150  ref_items.ref_count_p = new unsigned int(1);
1151  }
1152  catch (...) {
1153  delete ref_items.mutex_p;
1154  deleter(ptr);
1155  throw;
1156  }
1157 # endif
1158 #else
1159 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
1160  ref_items.ref_count_p = g_slice_new(gint);
1161  *ref_items.ref_count_p = 1;
1162 # else
1163  try {
1164  ref_items.ref_count_p = new gint(1);
1165  }
1166  catch (...) {
1167  deleter(ptr); // if allocating the int referenced by ref_items.ref_count_p
1168  // has failed then delete the object to be referenced to
1169  // avoid a memory leak
1170  throw;
1171  }
1172 # endif
1173 #endif
1174  }
1175  else {
1176 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1177  ref_items.mutex_p = 0; // make sure the value is valid as we may assign it
1178 #endif
1179  ref_items.ref_count_p = 0;
1180  }
1181  }
1182 
1183  /**
1184  * Constructor taking an unmanaged object.
1185  * @param ptr The object which the SharedLockHandle is to manage.
1186  * @param tag Passing the tag emumerator
1187  * Cgu::SharedHandleAllocFail::leave causes this constructor not to
1188  * delete the new managed object passed as the 'ptr' argument in the
1189  * event of internal allocation in this method failing because of
1190  * memory exhaustion (in that event, Cgu::SharedHandleError will be
1191  * thrown).
1192  * @exception Cgu::SharedHandleError This constructor might throw
1193  * Cgu::SharedHandleError if memory is exhausted and the system would
1194  * otherwise throw std::bad_alloc in that case. This constructor is
1195  * exception safe (it does not leak resources), and if such an
1196  * exception is thrown it will clean itself up, but it will not
1197  * attempt to delete the new managed object passed to it. Access to
1198  * the object passed to the 'ptr' argument can be obtained via the
1199  * thrown Cgu::SharedHandleError object.
1200  * @note 1. On systems with over-commit/lazy-commit combined with
1201  * virtual memory (swap), it is rarely useful to check for memory
1202  * exhaustion, so in those cases this version of the constructor will
1203  * not be useful.
1204  * @note 2. If the library has been installed using the
1205  * --with-glib-memory-slices-no-compat configuration option this
1206  * version of the constructor will also not be useful: instead glib
1207  * will terminate the program if it is unable to obtain memory from
1208  * the operating system.
1209  * @note 3. By default, glib atomic functions are used to provide
1210  * thread-safe manipulation of the reference count. However, a
1211  * library user can define the symbol CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1212  * before shared_handle.h is parsed so as to use mutexes instead,
1213  * which might be useful for some debugging purposes. Were she to do
1214  * so, Cgu::SharedHandleError might be thrown by this constructor if
1215  * initialization of the mutex fails (even if the
1216  * --with-glib-memory-slices-no-compat configuration option is
1217  * chosen), but it is usually not worth checking for such mutex
1218  * initialization failure.
1219  */
1221 
1222  if ((ref_items.obj = ptr)) { // not NULL
1223 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1224  try {
1225  ref_items.mutex_p = new Thread::Mutex;
1226  }
1227  catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly
1228  throw SharedHandleError<T>(ptr);
1229  }
1230  catch (Thread::MutexError&) { // as we are not rethrowing, make NPTL friendly
1231  throw SharedHandleError<T>(ptr);
1232  }
1233 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
1234  ref_items.ref_count_p = g_slice_new(unsigned int);
1235  *ref_items.ref_count_p = 1;
1236 # else
1237  try {
1238  ref_items.ref_count_p = new unsigned int(1);
1239  }
1240  catch (std::bad_alloc&) {
1241  delete ref_items.mutex_p;
1242  throw SharedHandleError<T>(ptr);
1243  }
1244 # endif
1245 #else
1246 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
1247  ref_items.ref_count_p = g_slice_new(gint);
1248  *ref_items.ref_count_p = 1;
1249 # else
1250  try {
1251  ref_items.ref_count_p = new gint(1);
1252  }
1253  catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly
1254  throw SharedHandleError<T>(ptr);
1255  }
1256 # endif
1257 #endif
1258  }
1259  else {
1260 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1261  ref_items.mutex_p = 0; // make sure the value is valid as we may assign it
1262 #endif
1263  ref_items.ref_count_p = 0;
1264  }
1265  }
1266 
1267 /**
1268  * Causes the SharedLockHandle to cease to manage its managed object
1269  * (if any), deleting it if this is the last ShareLockHandle object
1270  * managing it. If the argument passed is not NULL, the
1271  * SharedLockHandle object will manage the new object passed (which
1272  * must not be managed by any other SharedLockHandle object).
1273  * @param ptr NULL (the default), or a new unmanaged object to manage.
1274  * @exception std::bad_alloc This method will not throw if the 'ptr'
1275  * argument has a NULL value (the default) and the destructor of a
1276  * managed object does not throw, otherwise it might throw
1277  * std::bad_alloc if memory is exhausted and the system throws in that
1278  * case. Note that if such an exception is thrown then this method
1279  * will do nothing (it is strongly exception safe and will continue to
1280  * manage the object it was managing prior to the call), except that
1281  * it will delete the new managed object passed to it to avoid a
1282  * memory leak. If such automatic deletion in the event of such an
1283  * exception is not wanted, use the reset() method taking a
1284  * Cgu::SharedHandleAllocFail::Leave tag type as its second argument.
1285  * @note 1. std::bad_alloc will not be thrown if the library has been
1286  * installed using the --with-glib-memory-slices-no-compat
1287  * configuration option: instead glib will terminate the program if it
1288  * is unable to obtain memory from the operating system.
1289  * @note 2. By default, glib atomic functions are used to provide
1290  * thread-safe manipulation of the reference count. However, a
1291  * library user can define the symbol CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1292  * before shared_handle.h is parsed so as to use mutexes instead,
1293  * which might be useful for some debugging purposes. Were she to do
1294  * so, Cgu::Thread::MutexError might be thrown by this method if
1295  * initialization of the mutex fails, but it is usually not worth
1296  * checking for this.
1297  * @note 3. A SharedLockHandle object protects its reference count but
1298  * not the managed object or its other internals. The reset() method
1299  * should not be called by one thread in respect of a particular
1300  * SharedLockHandle object while another thread may be operating on,
1301  * copying or dereferencing the same instance of SharedLockHandle. It
1302  * is thread-safe as against another instance of SharedLockHandle
1303  * managing the same object.
1304  */
1305  void reset(T ptr = 0) {
1306  SharedLockHandle tmp(ptr);
1307  std::swap(ref_items, tmp.ref_items);
1308  }
1309 
1310 /**
1311  * Causes the SharedLockHandle to cease to manage its managed object
1312  * (if any), deleting it if this is the last ShareLockHandle object
1313  * managing it. The SharedLockHandle object will manage the new
1314  * object passed (which must not be managed by any other
1315  * SharedLockHandle object). This method is exception safe, but see
1316  * the comments below on Cgu::SharedHandleError.
1317  * @param ptr A new unmanaged object to manage (if no new object is to
1318  * be managed, use the version of reset() taking a default value of
1319  * NULL).
1320  * @param tag Passing the tag emumerator
1321  * Cgu::SharedHandleAllocFail::leave causes this method not to delete
1322  * the new managed object passed as the 'ptr' argument in the event of
1323  * internal allocation in this method failing because of memory
1324  * exhaustion (in that event, Cgu::SharedHandleError will be thrown).
1325  * @exception Cgu::SharedHandleError This method might throw
1326  * Cgu::SharedHandleError if memory is exhausted and the system would
1327  * otherwise throw std::bad_alloc in that case. Note that if such an
1328  * exception is thrown then this method will do nothing (it is
1329  * strongly exception safe and will continue to manage the object it
1330  * was managing prior to the call), and it will not attempt to delete
1331  * the new managed object passed to it (if any). Access to the object
1332  * passed to the 'ptr' argument can be obtained via the thrown
1333  * Cgu::SharedHandleError object.
1334  * @note 1. A SharedLockHandle object protects its reference count but
1335  * not the managed object or its other internals. The reset() method
1336  * should not be called by one thread in respect of a particular
1337  * SharedLockHandle object while another thread may be operating on,
1338  * copying or dereferencing the same instance of SharedLockHandle. It
1339  * is thread-safe as against another instance of SharedLockHandle
1340  * managing the same object.
1341  * @note 2. On systems with over-commit/lazy-commit combined with
1342  * virtual memory (swap), it is rarely useful to check for memory
1343  * exhaustion, so in those cases this version of the reset() method
1344  * will not be useful.
1345  * @note 3. If the library has been installed using the
1346  * --with-glib-memory-slices-no-compat configuration option this
1347  * version of the reset() method will also not be useful: instead glib
1348  * will terminate the program if it is unable to obtain memory from
1349  * the operating system.
1350  * @note 4. By default, glib atomic functions are used to provide
1351  * thread-safe manipulation of the reference count. However, a
1352  * library user can define the symbol CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1353  * before shared_handle.h is parsed so as to use mutexes instead,
1354  * which might be useful for some debugging purposes. Were she to do
1355  * so, Cgu::SharedHandleError might be thrown by this method if
1356  * initialization of the mutex fails (even if the
1357  * --with-glib-memory-slices-no-compat configuration option is
1358  * chosen), but it is usually not worth checking for such mutex
1359  * initialization failure.
1360  */
1362  SharedLockHandle tmp(ptr, tag);
1363  std::swap(ref_items, tmp.ref_items);
1364  }
1365 
1366  /**
1367  * The copy constructor does not throw.
1368  * @param sh_hand The handle to be copied.
1369  */
1371  ref_items = sh_hand.ref_items;
1372  reference();
1373  }
1374 
1375  /**
1376  * The move constructor does not throw. It has move semantics.
1377  * @param sh_hand The handle to be moved.
1378  */
1380  ref_items = sh_hand.ref_items;
1381 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1382  sh_hand.ref_items.mutex_p = 0; // make sure the value is valid as we may assign it
1383 #endif
1384  sh_hand.ref_items.ref_count_p = 0;
1385  sh_hand.ref_items.obj = 0;
1386  }
1387 
1388  /**
1389  * This method (and so copy or move assignment) does not throw unless
1390  * the destructor of a managed object throws.
1391  * @param sh_hand the assignor.
1392  * @return The SharedLockHandle object after assignment.
1393  */
1394  // having a value type as the argument, rather than reference to const
1395  // and then initialising a tmp object, gives the compiler more scope
1396  // for optimisation
1398  std::swap(ref_items, sh_hand.ref_items);
1399  return *this;
1400  }
1401 
1402  /**
1403  * This method does not throw.
1404  * @return A pointer to the handled object (or NULL if none is
1405  * handled).
1406  */
1407  T get() const {return ref_items.obj;}
1408 
1409  /**
1410  * This method does not throw.
1411  * @return A pointer to the handled object (or NULL if none is
1412  * handled).
1413  */
1414  operator T() const {return ref_items.obj;}
1415 
1416  /**
1417  * This method does not throw.
1418  * @return The number of SharedLockHandle objects referencing the
1419  * managed object (or 0 if none is managed by this SharedLockHandle).
1420  * @note The return value may not be valid if another thread has
1421  * changed the reference count before the value returned by this
1422  * method is acted on. It is provided as a utility, but may not be
1423  * meaningful, depending on the intended usage.
1424  */
1425  unsigned int get_refcount() const {
1426  if (!ref_items.ref_count_p) return 0;
1427 #ifdef CGU_SHARED_LOCK_HANDLE_USE_MUTEX
1428  Thread::Mutex::Lock lock(*ref_items.mutex_p);
1429  return *ref_items.ref_count_p;
1430 #else
1431  return g_atomic_int_get(ref_items.ref_count_p);
1432 #endif
1433  }
1434 
1435  /**
1436  * The destructor does not throw unless the destructor of a handled
1437  * object throws - that should never happen.
1438  */
1439  ~SharedLockHandle() {unreference();}
1440 };
1441 
1442 #if defined(CGU_USE_SMART_PTR_COMPARISON) || defined(DOXYGEN_PARSING)
1443 
1444 // we can use built-in operator == when comparing pointers referencing
1445 // different objects of the same type
1446 /**
1447  * @ingroup handles
1448  *
1449  * This comparison operator does not throw. It compares the addresses
1450  * of the managed objects.
1451  *
1452  * Since 2.0.0-rc2
1453  */
1454 template <class T, class Dealloc>
1456  return (s1.get() == s2.get());
1457 }
1458 
1459 /**
1460  * @ingroup handles
1461  *
1462  * This comparison operator does not throw. It compares the addresses
1463  * of the managed objects.
1464  *
1465  * Since 2.0.0-rc2
1466  */
1467 template <class T, class Dealloc>
1469  return !(s1 == s2);
1470 }
1471 
1472 // we must use std::less rather than the < built-in operator for
1473 // pointers to objects not within the same array or object: "For
1474 // templates greater, less, greater_equal, and less_equal, the
1475 // specializations for any pointer type yield a total order, even if
1476 // the built-in operators <, >, <=, >= do not." (para 20.3.3/8).
1477 /**
1478  * @ingroup handles
1479  *
1480  * This comparison operator does not throw. It compares the addresses
1481  * of the managed objects.
1482  *
1483  * Since 2.0.0-rc2
1484  */
1485 template <class T, class Dealloc>
1486 bool operator<(const SharedHandle<T, Dealloc>& s1, const SharedHandle<T, Dealloc>& s2) {
1487  return std::less<T>()(s1.get(), s2.get());
1488 }
1489 
1490 /**
1491  * @ingroup handles
1492  *
1493  * This comparison operator does not throw. It compares the addresses
1494  * of the managed objects.
1495  *
1496  * Since 2.0.0-rc2
1497  */
1498 template <class T, class Dealloc>
1500  return (s1.get() == s2.get());
1501 }
1502 
1503 /**
1504  * @ingroup handles
1505  *
1506  * This comparison operator does not throw. It compares the addresses
1507  * of the managed objects.
1508  *
1509  * Since 2.0.0-rc2
1510  */
1511 template <class T, class Dealloc>
1513  return !(s1 == s2);
1514 }
1515 
1516 /**
1517  * @ingroup handles
1518  *
1519  * This comparison operator does not throw. It compares the addresses
1520  * of the managed objects.
1521  *
1522  * Since 2.0.0-rc2
1523  */
1524 template <class T, class Dealloc>
1525 bool operator<(const SharedLockHandle<T, Dealloc>& s1, const SharedLockHandle<T, Dealloc>& s2) {
1526  return std::less<T>()(s1.get(), s2.get());
1527 }
1528 
1529 #endif // CGU_USE_SMART_PTR_COMPARISON
1530 
1531 } // namespace Cgu
1532 
1533 // doxygen produces long filenames that tar can't handle:
1534 // we have generic documentation for std::hash specialisations
1535 // in doxygen.main.in
1536 #if defined(CGU_USE_SMART_PTR_COMPARISON) && !defined(DOXYGEN_PARSING)
1537 /* These structs allow SharedHandle and SharedLockHandle objects to be
1538  keys in unordered associative containers */
1539 namespace std {
1540 template <class T, class Dealloc>
1541 struct hash<Cgu::SharedHandle<T, Dealloc>> {
1542  typedef std::size_t result_type;
1543  typedef Cgu::SharedHandle<T, Dealloc> argument_type;
1544  result_type operator()(const argument_type& s) const {
1545  // this is fine: std::hash structs do not normally contain data and
1546  // std::hash<T*> certainly won't, so we don't have overhead constructing
1547  // std::hash<T*> on the fly
1548  return std::hash<T>()(s.get());
1549  }
1550 };
1551 template <class T, class Dealloc>
1552 struct hash<Cgu::SharedLockHandle<T, Dealloc>> {
1553  typedef std::size_t result_type;
1554  typedef Cgu::SharedLockHandle<T, Dealloc> argument_type;
1555  result_type operator()(const argument_type& s) const {
1556  // this is fine: std::hash structs do not normally contain data and
1557  // std::hash<T*> certainly won't, so we don't have overhead constructing
1558  // std::hash<T*> on the fly
1559  return std::hash<T>()(s.get());
1560  }
1561 };
1562 } // namespace std
1563 #endif // CGU_USE_SMART_PTR_COMPARISON
1564 
1565 #endif