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