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