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