c++-gtk-utils
shared_ptr.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_PTR_H
40 #define CGU_SHARED_PTR_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 // SharedLockPtr class
45 /* #define CGU_SHARED_LOCK_PTR_USE_MUTEX 1 */
46 
47 #include <utility> // for std::move and std::swap
48 #include <exception>
49 #include <new>
50 #include <functional> // for std::less and std::hash<T*>
51 #include <cstddef> // for std::size_t
52 
53 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
54 #include <c++-gtk-utils/mutex.h>
55 #else
56 #include <glib.h>
57 #endif
58 
60 
61 /**
62  * @addtogroup handles handles and smart pointers
63  */
64 
65 namespace Cgu {
66 
67 /**
68  * @class SharedPtrError shared_ptr.h c++-gtk-utils/shared_ptr.h
69  * @brief This is an exception struct thrown as an alternative to
70  * deleting a managed object when internal memory allocation for
71  * SharedPtr or SharedLockPtr fails in their reset() method or in
72  * their constructor which takes a pointer.
73  * @ingroup handles
74  * @sa SharedPtr SharedLockPtr SharedPtrAllocFail
75  *
76  * This is an exception struct thrown as an alternative to deleting a
77  * managed object when SharedPtr<T>::SharedPtr(T*),
78  * SharedLockPtr<T>::SharedLockPtr(T*), SharedPtr<T>::reset(T*) or
79  * SharedLockPtr<T>::reset(T*), would otherwise throw std::bad_alloc.
80  * To make those methods do that, Cgu::SharedPtrAllocFail::leave is
81  * passed as their second argument.
82  *
83  * If the exception is thrown, the struct has a member 'obj' of type
84  * T*, which is a pointer to the object originally passed to those
85  * methods, so the user can deal with it appropriately. This enables
86  * the result of the new expression to be passed directly as the
87  * argument to those methods without giving rise to a resource leak,
88  * as in:
89  *
90  * @code
91  * using namespace Cgu;
92  * SharedPtr<T> s; // doesn't throw
93  * try {
94  * s.reset(new T, SharedPtrAllocFail::leave); // both T allocation and reset() might throw
95  * }
96  * catch (std::bad_alloc&) {
97  * ...
98  * }
99  * catch (SharedPtrError<T>& e) {
100  * e.obj->do_something();
101  * ...
102  * }
103  * ...
104  * @endcode
105  *
106  * As above, a catch block will need to deal with std::bad_alloc (if
107  * the call to the new expression when creating the T object fails)
108  * as well as SharedPtrError (if the call to the new expression in
109  * the reset() method fails after a valid T object has been
110  * constructed).
111  */
112 
113 template <class T> struct SharedPtrError: public std::exception {
114  T* obj;
115  virtual const char* what() const throw() {return "SharedPtrError\n";}
116  SharedPtrError(T* p): obj(p) {}
117 };
118 
119 /**
120  * enum Cgu::SharedPtrAllocFail::Leave
121  * The enumerator Cgu::SharedPtrAllocFail::leave is passed as the
122  * second argument of the reset() method of SharedPtr or
123  * SharedLockPtr, or in their constructor which takes a pointer, in
124  * order to prevent the method deleting the object passed to it if
125  * reset() fails internally because of memory exhaustion.
126  * @ingroup handles
127  */
128 namespace SharedPtrAllocFail {
129  enum Leave {leave};
130 }
131 
132 
133 /**
134  * @class SharedPtr shared_ptr.h c++-gtk-utils/shared_ptr.h
135  * @brief This is a smart pointer for managing the lifetime of objects
136  * allocated on freestore.
137  * @ingroup handles
138  * @sa SharedLockPtr SharedPtrError
139  *
140  * This is a smart pointer for managing the lifetime of objects
141  * allocated on freestore with the new expression. A managed object
142  * will be deleted when the last SharedPtr referencing it is
143  * destroyed.
144  *
145  * @b Comparison @b with @b std::shared_ptr
146  *
147  * Most of the things that can be done by this class can be done by
148  * using std::shared_ptr from C++11/14, but this class is retained in
149  * the c++-gtk-utils library not only to retain compatibility with
150  * series 1.2 of the library, but also to cater for some cases not met
151  * (or not so easily met) by std::shared_ptr:
152  *
153  * 1. Glib memory slices provide an efficient small object allocator
154  * (they are likely to be significantly more efficient than global
155  * operator new()/new[](), which generally hand off to malloc(),
156  * and whilst malloc() is good for large block allocations it is
157  * generally poor as a small object allocator). Internal
158  * Cgu::SharedPtr allocation using glib memory slices can be
159  * achieved by compiling the library with the
160  * \--with-glib-memory-slices-no-compat configuration option.
161  * 2. If glib memory slices are not used (which do not throw),
162  * constructing a shared pointer for a new managed object (or
163  * calling reset() for a new managed object) might throw if
164  * internal allocation fails. Although by default the
165  * Cgu::SharedPtr implementation will delete the new managed object
166  * in such a case, it also provides an alternative constructor and
167  * reset() method which instead enable the new object to be
168  * accessed via the thrown exception object so that user code can
169  * decide what to do; std::shared_ptr deletes the new object in
170  * every case.
171  * 3. A user can explicitly state whether the shared pointer object is
172  * to have atomic increment and decrement-and-test with respect to
173  * the reference count so that the reference count is thread safe
174  * ('no' in the case of Cgu::SharedPtr, and 'yes' in the case of
175  * Cgu::SharedLockPtr). Using atomic functions is unnecessary if
176  * the managed object concerned is only addressed in one thread
177  * (and might cause unwanted cache flushing in certain
178  * circumstances). std::shared_ptr will generally always use
179  * atomic functions with respect to its reference count in a
180  * multi-threaded program.
181  *
182  * In favour of std::shared_ptr, it has an associated
183  * std::make_shared() factory function which will construct both the
184  * referenced object and the shared pointer's reference count within a
185  * single memory block when the first shared pointer managing a
186  * particular object is constructed. Cgu::SharedPtr and
187  * Cgu::SharedLockPtr always allocate these separately, but this is
188  * partly mitigated by the use of glib memory slices to allocate the
189  * reference count where the \--with-glib-memory-slices-no-compat
190  * configuration option is chosen.
191  *
192  * In addition, std::shared_ptr has an associated std::weak_ptr class,
193  * which Cgu::SharedPtr does not (there is a Cgu::GobjWeakHandle
194  * class, but that is cognate with Cgu::GobjHandle and is only usable
195  * with GObjects).
196  *
197  * If the library is compiled with the
198  * \--with-glib-memory-slices-no-compat configuration option, as
199  * mentioned Cgu::SharedPtr constructs its reference counting
200  * internals using glib memory slices. Although it is safe in a
201  * multi-threaded program if glib < 2.32 is installed to construct a
202  * static SharedPtr object in global namespace (that is, prior to
203  * g_thread_init() being called) by means of the default constructor
204  * and/or a pointer argument of NULL, it is not safe if constructed
205  * with a non-NULL pointer value. If glib >= 2.32 is installed,
206  * global objects with memory slices are safe in all
207  * circumstances. (Having said that, it would be highly unusual to
208  * have global SharedPtr objects.)
209  */
210 
211 template <class T> class SharedPtr {
212 
213 #ifndef DOXYGEN_PARSING
214  struct RefItems {
215  unsigned int* ref_count_p;
216  T* obj_p;
217  } ref_items;
218 #endif
219 
220  void unreference() {
221  if (!ref_items.ref_count_p) return;
222  --(*ref_items.ref_count_p);
223  if (*ref_items.ref_count_p == 0) {
224 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
225  g_slice_free(unsigned int, ref_items.ref_count_p);
226 #else
227  delete ref_items.ref_count_p;
228 #endif
229  delete ref_items.obj_p;
230  }
231  }
232 
233  void reference() noexcept {
234  if (!ref_items.ref_count_p) return;
235  ++(*ref_items.ref_count_p);
236  }
237 
238 public:
239 /**
240  * Constructor taking an unmanaged object.
241  * @param ptr The object which the SharedPtr is to manage (if any).
242  * @exception std::bad_alloc This constructor will not throw if the
243  * 'ptr' argument has a NULL value (the default), otherwise it might
244  * throw std::bad_alloc if memory is exhausted and the system throws
245  * in that case. If such an exception is thrown, this constructor is
246  * exception safe (it does not leak resources), but as well as
247  * cleaning itself up this constructor will also delete the managed
248  * object passed to it to avoid a memory leak. If such automatic
249  * deletion is not wanted in that case, use the version of this
250  * constructor taking a Cgu::SharedPtrAllocFail::Leave tag argument.
251  * @note std::bad_alloc will not be thrown if the library has been
252  * installed using the \--with-glib-memory-slices-no-compat
253  * configuration option: instead glib will terminate the program if it
254  * is unable to obtain memory from the operating system.
255  */
256  explicit SharedPtr(T* ptr = 0) {
257 
258  if ((ref_items.obj_p = ptr)) { // not NULL
259 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
260  ref_items.ref_count_p = g_slice_new(unsigned int);
261  *ref_items.ref_count_p = 1;
262 #else
263  try {
264  ref_items.ref_count_p = new unsigned int(1);
265  }
266  catch (...) {
267  delete ptr; // if allocating the int referenced by ref_items.ref_count_p
268  // has failed then delete the object to be referenced to
269  // avoid a memory leak
270  throw;
271  }
272 #endif
273  }
274  else ref_items.ref_count_p = 0;
275  }
276 
277 /**
278  * Constructor taking an unmanaged object.
279  * @param ptr The object which the SharedPtr is to manage.
280  * @param tag Passing the tag emumerator
281  * Cgu::SharedPtrAllocFail::leave causes this constructor not to
282  * delete the new managed object passed as the 'ptr' argument in the
283  * event of internal allocation in this method failing because of
284  * memory exhaustion (in that event, Cgu::SharedPtrError will be
285  * thrown).
286  * @exception Cgu::SharedPtrError This constructor might throw
287  * Cgu::SharedPtrError if memory is exhausted and the system would
288  * otherwise throw std::bad_alloc in that case. This constructor is
289  * exception safe (it does not leak resources), and if such an
290  * exception is thrown it will clean itself up, but it will not
291  * attempt to delete the new managed object passed to it. Access to
292  * the object passed to the 'ptr' argument can be obtained via the
293  * thrown Cgu::SharedPtrError object.
294  * @note 1. On systems with over-commit/lazy-commit combined with
295  * virtual memory (swap), it is rarely useful to check for memory
296  * exhaustion, so in those cases this version of the constructor will
297  * not be useful.
298  * @note 2. If the library has been installed using the
299  * \--with-glib-memory-slices-no-compat configuration option this
300  * version of the constructor will also not be useful: instead glib
301  * will terminate the program if it is unable to obtain memory from
302  * the operating system.
303  */
305 
306  if ((ref_items.obj_p = ptr)) { // not NULL
307 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
308  ref_items.ref_count_p = g_slice_new(unsigned int);
309  *ref_items.ref_count_p = 1;
310 #else
311  try {
312  ref_items.ref_count_p = new unsigned int(1);
313  }
314  catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly
315  throw SharedPtrError<T>(ptr);
316  }
317 #endif
318  }
319  else ref_items.ref_count_p = 0;
320  }
321 
322 /**
323  * Causes the SharedPtr to cease to manage its managed object (if
324  * any), deleting it if this is the last SharedPtr object managing it.
325  * If the argument passed is not NULL, the SharedPtr object will
326  * manage the new object passed (which must not be managed by any
327  * other SharedPtr object). This method is exception safe, but see
328  * the comments below on std::bad_alloc.
329  * @param ptr NULL (the default), or a new unmanaged object to manage.
330  * @exception std::bad_alloc This method will not throw if the 'ptr'
331  * argument has a NULL value (the default) and the destructor of a
332  * managed object does not throw, otherwise it might throw
333  * std::bad_alloc if memory is exhausted and the system throws in that
334  * case. Note that if such an exception is thrown then this method
335  * will do nothing (it is strongly exception safe and will continue to
336  * manage the object it was managing prior to the call), except that
337  * it will delete the new managed object passed to it to avoid a
338  * memory leak. If such automatic deletion in the event of such an
339  * exception is not wanted, use the reset() method taking a
340  * Cgu::SharedPtrAllocFail::Leave tag type as its second argument.
341  * @note std::bad_alloc will not be thrown if the library has been
342  * installed using the \--with-glib-memory-slices-no-compat
343  * configuration option: instead glib will terminate the program if it
344  * is unable to obtain memory from the operating system.
345  */
346  void reset(T* ptr = 0) {
347  SharedPtr tmp(ptr);
348  std::swap(ref_items, tmp.ref_items);
349  }
350 
351 /**
352  * Causes the SharedPtr to cease to manage its managed object (if
353  * any), deleting it if this is the last SharedPtr object managing it.
354  * The SharedPtr object will manage the new object passed (which must
355  * not be managed by any other SharedPtr object). This method is
356  * exception safe, but see the comments below on Cgu::SharedPtrError.
357  * @param ptr A new unmanaged object to manage (if no new object is to
358  * be managed, use the version of reset() taking a default value of
359  * NULL).
360  * @param tag Passing the tag emumerator
361  * Cgu::SharedPtrAllocFail::leave causes this method not to delete the
362  * new managed object passed as the 'ptr' argument in the event of
363  * internal allocation in this method failing because of memory
364  * exhaustion (in that event, Cgu::SharedPtrError will be thrown).
365  * @exception Cgu::SharedPtrError This method might throw
366  * Cgu::SharedPtrError if memory is exhausted and the system would
367  * otherwise throw std::bad_alloc in that case. Note that if such an
368  * exception is thrown then this method will do nothing (it is
369  * strongly exception safe and will continue to manage the object it
370  * was managing prior to the call), and it will not attempt to delete
371  * the new managed object passed to it. Access to the object passed
372  * to the 'ptr' argument can be obtained via the thrown
373  * Cgu::SharedPtrError object.
374  * @note 1. On systems with over-commit/lazy-commit combined with
375  * virtual memory (swap), it is rarely useful to check for memory
376  * exhaustion, so in those cases this version of the reset() method
377  * will not be useful.
378  * @note 2. If the library has been installed using the
379  * \--with-glib-memory-slices-no-compat configuration option this
380  * version of the reset() method will also not be useful: instead glib
381  * will terminate the program if it is unable to obtain memory from
382  * the operating system.
383  */
385  SharedPtr tmp(ptr, tag);
386  std::swap(ref_items, tmp.ref_items);
387  }
388 
389  /**
390  * This copy constructor does not throw.
391  * @param sh_ptr The shared pointer to be copied.
392  */
393  SharedPtr(const SharedPtr& sh_ptr) noexcept {
394  ref_items = sh_ptr.ref_items;
395  reference();
396  }
397 
398  /**
399  * The move constructor does not throw. It has move semantics.
400  * @param sh_ptr The shared pointer to be moved.
401  */
402  SharedPtr(SharedPtr&& sh_ptr) noexcept {
403  ref_items = sh_ptr.ref_items;
404  sh_ptr.ref_items.ref_count_p = 0;
405  sh_ptr.ref_items.obj_p = 0;
406  }
407 
408  template <class U> friend class SharedPtr;
409 
410  /**
411  * A version of the copy constructor which enables pointer type
412  * conversion (assuming the type passed is implicitly type
413  * convertible to the managed type, such as a derived type). This
414  * copy constructor does not throw.
415  * @param sh_ptr The shared pointer to be copied.
416  */
417  template <class U> SharedPtr(const SharedPtr<U>& sh_ptr) noexcept {
418  // because we are allowing an implicit cast from derived to
419  // base class referenced object, we need to assign from each
420  // member of sh_ptr.ref_items separately
421  ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p;
422  ref_items.obj_p = sh_ptr.ref_items.obj_p;
423  reference();
424  }
425 
426  /**
427  * A version of the move constructor which enables pointer type
428  * conversion (assuming the type passed is implicitly type
429  * convertible to the managed type, such as a derived type). This
430  * move constructor does not throw.
431  * @param sh_ptr The shared pointer to be moved.
432  */
433  template <class U> SharedPtr(SharedPtr<U>&& sh_ptr) noexcept {
434  // because we are allowing an implicit cast from derived to
435  // base class referenced object, we need to assign from each
436  // member of sh_ptr.ref_items separately
437  ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p;
438  ref_items.obj_p = sh_ptr.ref_items.obj_p;
439  sh_ptr.ref_items.ref_count_p = 0;
440  sh_ptr.ref_items.obj_p = 0;
441  }
442 
443  /**
444  * This method (and so copy or move assignment) does not throw unless
445  * the destructor of a managed object throws.
446  * @param sh_ptr the assignor.
447  * @return The SharedPtr object after assignment.
448  */
449  // having a value type as the argument, rather than reference to const
450  // and then initialising a tmp object, gives the compiler more scope
451  // for optimisation, and also caters for r-values without a separate
452  // overload
454  std::swap(ref_items, sh_ptr.ref_items);
455  return *this;
456  }
457 
458  /**
459  * A version of the assignment operator which enables pointer type
460  * conversion (assuming the type passed is implicitly type
461  * convertible to the managed type, such as a derived type). This
462  * method does not throw unless the destructor of a managed object
463  * throws.
464  * @param sh_ptr the assignor.
465  * @return The SharedPtr object after assignment.
466  */
467  template <class U> SharedPtr& operator=(const SharedPtr<U>& sh_ptr) {
468  return operator=(SharedPtr(sh_ptr));
469  }
470 
471  /**
472  * A version of the operator for move assignment which enables
473  * pointer type conversion (assuming the type passed is implicitly
474  * type convertible to the managed type, such as a derived type).
475  * This method does not throw unless the destructor of a managed
476  * object throws.
477  * @param sh_ptr the shared pointer to be moved.
478  * @return The SharedPtr object after the move operation.
479  */
480  template <class U> SharedPtr& operator=(SharedPtr<U>&& sh_ptr) {
481  return operator=(SharedPtr(std::move(sh_ptr)));
482  }
483 
484  /**
485  * This method does not throw.
486  * @return A pointer to the managed object (or NULL if none is
487  * managed).
488  */
489  T* get() const noexcept {return ref_items.obj_p;}
490 
491  /**
492  * This method does not throw.
493  * @return A reference to the managed object.
494  */
495  T& operator*() const noexcept {return *ref_items.obj_p;}
496 
497  /**
498  * This method does not throw.
499  * @return A pointer to the managed object (or NULL if none is
500  * managed).
501  */
502  T* operator->() const noexcept {return ref_items.obj_p;}
503 
504  /**
505  * This method does not throw.
506  * @return The number of SharedPtr objects referencing the managed
507  * object (or 0 if none is managed by this SharedPtr).
508  */
509  unsigned int get_refcount() const noexcept {return (ref_items.ref_count_p) ? *ref_items.ref_count_p : 0;}
510 
511  /**
512  * The destructor does not throw unless the destructor of a managed
513  * object throws - that should never happen.
514  */
515  ~SharedPtr() {unreference();}
516 };
517 
518 /**
519  * @class SharedLockPtr shared_ptr.h c++-gtk-utils/shared_ptr.h
520  * @brief This is a smart pointer for managing the lifetime of objects
521  * allocated on freestore, with a thread safe reference count.
522  * @ingroup handles
523  * @sa SharedPtr SharedPtrError
524  *
525  * Class SharedLockPtr is a version of the shared pointer class which
526  * includes synchronization so that it can handle objects accessed in
527  * multiple threads (although the word Lock is in the title, by
528  * default it uses glib atomic functions to access the reference count
529  * rather than a mutex, so the overhead should be very small). Note
530  * that only the reference count is protected, so this is thread safe
531  * in the sense in which a raw pointer is thread safe. A shared
532  * pointer accessed in one thread referencing a particular object is
533  * thread safe as against another shared pointer accessing the same
534  * object in a different thread. It is thus suitable for use in
535  * different standard C++ containers which exist in different threads
536  * but which contain shared objects by reference. But:
537  *
538  * 1. If the referenced object is to be modified in one thread and
539  * read or modified in another thread an appropriate mutex for the
540  * referenced object is required (unless that referenced object
541  * does its own locking).
542  * 2. If the same instance of shared pointer is to be modified in one
543  * thread (by assigning to the pointer so that it references a
544  * different object, or by moving from it), and copied (assigned
545  * from or used as the argument of a copy constructor), accessed,
546  * destroyed or modified in another thread, a mutex for that
547  * instance of shared pointer is required.
548  * 3. Objects referenced by shared pointers which are objects for
549  * which POSIX provides no guarantees (in the main, those which
550  * are not built-in types), such as strings and similar
551  * containers, may not support concurrent reads in different
552  * threads. That depends on the library implementation concerned
553  * (but a fully conforming C++11 library implementation is
554  * required to permit concurrent calls to the const methods of any
555  * object from the standard library without external
556  * synchronization, so long as no non-const method is called
557  * concurrently). For cases where concurrent reads are not
558  * supported, a mutex for the referenced object will be required
559  * when reading any given instance of such an object in more than
560  * one thread by dereferencing any shared pointers referencing it
561  * (and indeed, when not using shared pointers at all).
562  *
563  * As mentioned, by default glib atomic functions are used to provide
564  * thread-safe manipulation of the reference count. However, the
565  * symbol CGU_SHARED_LOCK_PTR_USE_MUTEX can be defined so that the
566  * library uses mutexes instead, which might be useful for some
567  * debugging purposes. Note that if CGU_SHARED_LOCK_PTR_USE_MUTEX is
568  * to be defined, this is best done by textually amending the
569  * shared_ptr.h header file before the library is compiled. This will
570  * ensure that everything in the program and the library which
571  * includes the shared_ptr.h header is guaranteed to see the same
572  * definitions so that the C++ standard's one-definition-rule is
573  * complied with.
574  *
575  * @b Comparison @b with @b std::shared_ptr
576  *
577  * Most of the things that can be done by this class can be done by
578  * using std::shared_ptr from C++11/14, but this class is retained in
579  * the c++-gtk-utils library not only to retain compatibility with
580  * series 1.2 of the library, but also to cater for some cases not met
581  * (or not so easily met) by std::shared_ptr:
582  *
583  * 1. Glib memory slices provide an efficient small object allocator
584  * (they are likely to be significantly more efficient than global
585  * operator new()/new[](), which generally hand off to malloc(),
586  * and whilst malloc() is good for large block allocations it is
587  * generally poor as a small object allocator). Internal
588  * Cgu::SharedLockPtr allocation using glib memory slices can be
589  * achieved by compiling the library with the
590  * \--with-glib-memory-slices-no-compat configuration option.
591  * 2. If glib memory slices are not used (which do not throw),
592  * constructing a shared pointer for a new managed object (or
593  * calling reset() for a new managed object) might throw if
594  * internal allocation fails. Although by default the
595  * Cgu::SharedLockPtr implementation will delete the new managed
596  * object in such a case, it also provides an alternative
597  * constructor and reset() method which instead enable the new
598  * object to be accessed via the thrown exception object so that
599  * user code can decide what to do; std::shared_ptr deletes the new
600  * object in every case.
601  * 3. A user can explicitly state whether the shared pointer object is
602  * to have atomic increment and decrement-and-test with respect to
603  * the reference count so that the reference count is thread safe
604  * ('no' in the case of Cgu::SharedPtr, and 'yes' in the case of
605  * Cgu::SharedLockPtr). Using atomic functions is unnecessary if
606  * the managed object concerned is only addressed in one thread
607  * (and might cause unwanted cache flushing in certain
608  * circumstances). std::shared_ptr will generally always use
609  * atomic functions with respect to its reference count in a
610  * multi-threaded program.
611  *
612  * In favour of std::shared_ptr, it has an associated
613  * std::make_shared() factory function which will construct both the
614  * referenced object and the shared pointer's reference count within a
615  * single memory block when the first shared pointer managing a
616  * particular object is constructed. Cgu::SharedPtr and
617  * Cgu::SharedLockPtr always allocate these separately, but this is
618  * partly mitigated by the use of glib memory slices to allocate the
619  * reference count where the \--with-glib-memory-slices-no-compat
620  * configuration option is chosen.
621  *
622  * In addition, std::shared_ptr has an associated std::weak_ptr class,
623  * which Cgu::SharedLockPtr does not (there is a Cgu::GobjWeakHandle
624  * class, but that is cognate with Cgu::GobjHandle and is only usable
625  * with GObjects), and shared_ptr objects also have some atomic store,
626  * load and exchange functions provided for them which enable
627  * concurrent modifications of the same instance of shared_ptr in
628  * different threads to have defined results.
629  *
630  * If the library is compiled with the
631  * \--with-glib-memory-slices-no-compat configuration option, as
632  * mentioned Cgu::SharedLockPtr constructs its reference counting
633  * internals using glib memory slices. Although it is safe in a
634  * multi-threaded program if glib < 2.32 is installed to construct a
635  * static SharedLockPtr object in global namespace (that is, prior to
636  * g_thread_init() being called) by means of the default constructor
637  * and/or a pointer argument of NULL, it is not safe if constructed
638  * with a non-NULL pointer value. If glib >= 2.32 is installed,
639  * global objects with memory slices are safe in all
640  * circumstances. (Having said that, it would be highly unusual to
641  * have global SharedLockPtr objects.)
642  */
643 
644 template <class T> class SharedLockPtr {
645 
646 #ifndef DOXYGEN_PARSING
647  struct RefItems {
648 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
649  Thread::Mutex* mutex_p;
650  unsigned int* ref_count_p;
651 #else
652  gint* ref_count_p;
653 #endif
654  T* obj_p;
655  } ref_items;
656 #endif
657 
658  // SharedLockPtr<T>::unreference() does not throw if the destructor of the
659  // contained object does not throw, because Thread::Mutex::~Mutex(),
660  // Thread::Mutex::lock() and Thread::Mutex::unlock() do not throw
661  void unreference() {
662  // we can (and should) check whether ref_items.ref_count_p is NULL without
663  // a lock, because that member is specific to this SharedLockPtr object.
664  // Only the integer pointed to by it is shared amongst SharedLockPtr
665  // objects and requires locking
666  if (!ref_items.ref_count_p) return;
667 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
668  ref_items.mutex_p->lock();
669  --(*ref_items.ref_count_p);
670  if (*ref_items.ref_count_p == 0) {
671 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
672  g_slice_free(unsigned int, ref_items.ref_count_p);
673 # else
674  delete ref_items.ref_count_p;
675 # endif
676  ref_items.mutex_p->unlock();
677  delete ref_items.mutex_p;
678  delete ref_items.obj_p;
679  }
680  else ref_items.mutex_p->unlock();
681 #else
682  if (g_atomic_int_dec_and_test(ref_items.ref_count_p)) {
683 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
684  g_slice_free(gint, ref_items.ref_count_p);
685 # else
686  delete ref_items.ref_count_p;
687 # endif
688  delete ref_items.obj_p;
689  }
690 #endif
691  }
692 
693  // SharedLockPtr<T>::reference() does not throw because
694  // Thread::Mutex::Lock::Lock() and Thread::Mutex::Lock::~Lock() do not throw
695  void reference() noexcept {
696  // we can (and should) check whether ref_items.ref_count_p is NULL without
697  // a lock, because that member is specific to this SharedLockPtr object.
698  // Only the integer pointed to by it is shared amongst SharedLockPtr
699  // objects and requires locking
700  if (!ref_items.ref_count_p) return;
701 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
702  Thread::Mutex::Lock lock(*ref_items.mutex_p);
703  ++(*ref_items.ref_count_p);
704 #else
705  g_atomic_int_inc(ref_items.ref_count_p);
706 #endif
707  }
708 
709 public:
710 /**
711  * Constructor taking an unmanaged object.
712  * @param ptr The object which the SharedLockPtr is to manage (if
713  * any).
714  * @exception std::bad_alloc This constructor will not throw if the
715  * 'ptr' argument has a NULL value (the default), otherwise it might
716  * throw std::bad_alloc if memory is exhausted and the system throws
717  * in that case. If such an exception is thrown, this constructor is
718  * exception safe (it does not leak resources), but as well as
719  * cleaning itself up this constructor will also delete the managed
720  * object passed to it to avoid a memory leak. If such automatic
721  * deletion is not wanted in that case, use the version of this
722  * constructor taking a Cgu::SharedPtrAllocFail::Leave tag argument.
723  * @note 1. std::bad_alloc will not be thrown if the library has been
724  * installed using the \--with-glib-memory-slices-no-compat
725  * configuration option: instead glib will terminate the program if it
726  * is unable to obtain memory from the operating system.
727  * @note 2. By default, glib atomic functions are used to provide
728  * thread-safe manipulation of the reference count. However, the
729  * header file shared_ptr.h can be textually amended before the
730  * library is compiled to define the symbol
731  * CGU_SHARED_LOCK_PTR_USE_MUTEX so as to use mutexes instead, which
732  * might be useful for some debugging purposes. Were that to be done,
733  * Cgu::Thread::MutexError might be thrown by this constructor if
734  * initialization of the mutex fails.
735  */
736  explicit SharedLockPtr(T* ptr = 0) {
737 
738  if ((ref_items.obj_p = ptr)) { // not NULL
739 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
740  try {
741  ref_items.mutex_p = new Thread::Mutex;
742  }
743  catch (...) {
744  delete ptr; // if allocating the object referenced by ref_items.mutex_p
745  // has failed then delete the object to be referenced to
746  // avoid a memory leak
747  throw;
748  }
749 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
750  ref_items.ref_count_p = g_slice_new(unsigned int);
751  *ref_items.ref_count_p = 1;
752 # else
753  try {
754  ref_items.ref_count_p = new unsigned int(1);
755  }
756  catch (...) {
757  delete ref_items.mutex_p;
758  delete ptr;
759  throw;
760  }
761 # endif
762 #else
763 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
764  ref_items.ref_count_p = g_slice_new(gint);
765  *ref_items.ref_count_p = 1;
766 # else
767  try {
768  ref_items.ref_count_p = new gint(1);
769  }
770  catch (...) {
771  delete ptr; // if allocating the int referenced by ref_items.ref_count_p
772  // has failed then delete the object to be referenced to
773  // avoid a memory leak
774  throw;
775  }
776 # endif
777 #endif
778  }
779  else {
780 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
781  ref_items.mutex_p = 0; // make sure the value is valid as we may assign it
782 #endif
783  ref_items.ref_count_p = 0;
784  }
785  }
786 
787 /**
788  * Constructor taking an unmanaged object.
789  * @param ptr The object which the SharedLockPtr is to manage.
790  * @param tag Passing the tag emumerator
791  * Cgu::SharedPtrAllocFail::leave causes this constructor not to
792  * delete the new managed object passed as the 'ptr' argument in the
793  * event of internal allocation in this method failing because of
794  * memory exhaustion (in that event, Cgu::SharedPtrError will be
795  * thrown).
796  * @exception Cgu::SharedPtrError This constructor might throw
797  * Cgu::SharedPtrError if memory is exhausted and the system would
798  * otherwise throw std::bad_alloc in that case. This constructor is
799  * exception safe (it does not leak resources), and if such an
800  * exception is thrown it will clean itself up, but it will not
801  * attempt to delete the new managed object passed to it. Access to
802  * the object passed to the 'ptr' argument can be obtained via the
803  * thrown Cgu::SharedPtrError object.
804  * @note 1. On systems with over-commit/lazy-commit combined with
805  * virtual memory (swap), it is rarely useful to check for memory
806  * exhaustion, so in those cases this version of the constructor will
807  * not be useful.
808  * @note 2. If the library has been installed using the
809  * \--with-glib-memory-slices-no-compat configuration option this
810  * version of the constructor will also not be useful: instead glib
811  * will terminate the program if it is unable to obtain memory from
812  * the operating system.
813  * @note 3. By default, glib atomic functions are used to provide
814  * thread-safe manipulation of the reference count. However, the
815  * header file shared_ptr.h can be textually amended before the
816  * library is compiled to define the symbol
817  * CGU_SHARED_LOCK_PTR_USE_MUTEX so as to use mutexes instead, which
818  * might be useful for some debugging purposes. Were that to be done,
819  * Cgu::SharedPtrError might be thrown by this constructor if
820  * initialization of the mutex fails (even if the
821  * \--with-glib-memory-slices-no-compat configuration option is
822  * chosen).
823  */
825 
826  if ((ref_items.obj_p = ptr)) { // not NULL
827 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
828  try {
829  ref_items.mutex_p = new Thread::Mutex;
830  }
831  catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly
832  throw SharedPtrError<T>(ptr);
833  }
834  catch (Thread::MutexError&) { // as we are not rethrowing, make NPTL friendly
835  throw SharedPtrError<T>(ptr);
836  }
837 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
838  ref_items.ref_count_p = g_slice_new(unsigned int);
839  *ref_items.ref_count_p = 1;
840 # else
841  try {
842  ref_items.ref_count_p = new unsigned int(1);
843  }
844  catch (std::bad_alloc&) {
845  delete ref_items.mutex_p;
846  throw SharedPtrError<T>(ptr);
847  }
848 # endif
849 #else
850 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
851  ref_items.ref_count_p = g_slice_new(gint);
852  *ref_items.ref_count_p = 1;
853 # else
854  try {
855  ref_items.ref_count_p = new gint(1);
856  }
857  catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly
858  throw SharedPtrError<T>(ptr);
859  }
860 # endif
861 #endif
862  }
863  else {
864 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
865  ref_items.mutex_p = 0; // make sure the value is valid as we may assign it
866 #endif
867  ref_items.ref_count_p = 0;
868  }
869  }
870 
871 /**
872  * Causes the SharedLockPtr to cease to manage its managed object (if
873  * any), deleting it if this is the last SharedLockPtr object managing
874  * it. If the argument passed is not NULL, the SharedLockPtr object
875  * will manage the new object passed (which must not be managed by any
876  * other SharedLockPtr object). This method is exception safe, but
877  * see the comments below on std::bad_alloc.
878  * @param ptr NULL (the default), or a new unmanaged object to manage.
879  * @exception std::bad_alloc This method will not throw if the 'ptr'
880  * argument has a NULL value (the default) and the destructor of a
881  * managed object does not throw, otherwise it might throw
882  * std::bad_alloc if memory is exhausted and the system throws in that
883  * case. Note that if such an exception is thrown then this method
884  * will do nothing (it is strongly exception safe and will continue to
885  * manage the object it was managing prior to the call), except that
886  * it will delete the new managed object passed to it to avoid a
887  * memory leak. If such automatic deletion in the event of such an
888  * exception is not wanted, use the reset() method taking a
889  * Cgu::SharedPtrAllocFail::Leave tag type as its second argument.
890  * @note 1. std::bad_alloc will not be thrown if the library has been
891  * installed using the \--with-glib-memory-slices-no-compat
892  * configuration option: instead glib will terminate the program if it
893  * is unable to obtain memory from the operating system.
894  * @note 2. By default, glib atomic functions are used to provide
895  * thread-safe manipulation of the reference count. However, the
896  * header file shared_ptr.h can be textually amended before the
897  * library is compiled to define the symbol
898  * CGU_SHARED_LOCK_PTR_USE_MUTEX so as to use mutexes instead, which
899  * might be useful for some debugging purposes. Were that to be done,
900  * Cgu::Thread::MutexError might be thrown by this method if
901  * initialization of the mutex fails.
902  * @note 3. A SharedLockPtr object protects its reference count but
903  * not the managed object or its other internals. The reset() method
904  * should not be called by one thread in respect of a particular
905  * SharedLockPtr object while another thread may be operating on,
906  * copying or dereferencing the same instance of SharedLockPtr. It is
907  * thread-safe as against another instance of SharedLockPtr managing
908  * the same object.
909  */
910  void reset(T* ptr = 0) {
911  SharedLockPtr tmp(ptr);
912  std::swap(ref_items, tmp.ref_items);
913  }
914 
915 /**
916  * Causes the SharedLockPtr to cease to manage its managed object (if
917  * any), deleting it if this is the last SharedLockPtr object managing
918  * it. The SharedLockPtr object will manage the new object passed
919  * (which must not be managed by any other SharedLockPtr object).
920  * This method is exception safe, but see the comments below on
921  * Cgu::SharedPtrError.
922  * @param ptr A new unmanaged object to manage (if no new object is to
923  * be managed, use the version of reset() taking a default value of
924  * NULL).
925  * @param tag Passing the tag emumerator
926  * Cgu::SharedPtrAllocFail::leave causes this method not to delete the
927  * new managed object passed as the 'ptr' argument in the event of
928  * internal allocation in this method failing because of memory
929  * exhaustion (in that event, Cgu::SharedPtrError will be thrown).
930  * @exception Cgu::SharedPtrError This method might throw
931  * Cgu::SharedPtrError if memory is exhausted and the system would
932  * otherwise throw std::bad_alloc in that case. Note that if such an
933  * exception is thrown then this method will do nothing (it is
934  * strongly exception safe and will continue to manage the object it
935  * was managing prior to the call), and it will not attempt to delete
936  * the new managed object passed to it. Access to the object passed
937  * to the 'ptr' argument can be obtained via the thrown
938  * Cgu::SharedPtrError object.
939  * @note 1. A SharedLockPtr object protects its reference count but
940  * not the managed object or its other internals. The reset() method
941  * should not be called by one thread in respect of a particular
942  * SharedLockPtr object while another thread may be operating on,
943  * copying or dereferencing the same instance of SharedLockPtr. It is
944  * thread-safe as against another instance of SharedLockPtr managing
945  * the same object.
946  * @note 2. On systems with over-commit/lazy-commit combined with
947  * virtual memory (swap), it is rarely useful to check for memory
948  * exhaustion, so in those cases this version of the reset() method
949  * will not be useful.
950  * @note 3. If the library has been installed using the
951  * \--with-glib-memory-slices-no-compat configuration option this
952  * version of the reset() method will also not be useful: instead glib
953  * will terminate the program if it is unable to obtain memory from
954  * the operating system.
955  * @note 4. By default, glib atomic functions are used to provide
956  * thread-safe manipulation of the reference count. However, the
957  * header file shared_ptr.h can be textually amended before the
958  * library is compiled to define the symbol
959  * CGU_SHARED_LOCK_PTR_USE_MUTEX so as to use mutexes instead, which
960  * might be useful for some debugging purposes. Were that to be done,
961  * Cgu::SharedPtrError might be thrown by this method if
962  * initialization of the mutex fails (even if the
963  * \--with-glib-memory-slices-no-compat configuration option is
964  * chosen).
965  */
967  SharedLockPtr tmp(ptr, tag);
968  std::swap(ref_items, tmp.ref_items);
969  }
970 
971  /**
972  * This copy constructor does not throw.
973  * @param sh_ptr The shared pointer to be copied.
974  */
975  SharedLockPtr(const SharedLockPtr& sh_ptr) noexcept {
976  ref_items = sh_ptr.ref_items;
977  reference();
978  }
979 
980  /**
981  * The move constructor does not throw. It has move semantics.
982  * @param sh_ptr The shared pointer to be moved.
983  */
984  SharedLockPtr(SharedLockPtr&& sh_ptr) noexcept {
985  ref_items = sh_ptr.ref_items;
986 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
987  sh_ptr.ref_items.mutex_p = 0; // make sure the value is valid as we may assign it
988 #endif
989  sh_ptr.ref_items.ref_count_p = 0;
990  sh_ptr.ref_items.obj_p = 0;
991  }
992 
993  template <class U> friend class SharedLockPtr;
994 
995  /**
996  * A version of the copy constructor which enables pointer type
997  * conversion (assuming the type passed is implicitly type
998  * convertible to the managed type, such as a derived type). This
999  * copy constructor does not throw.
1000  * @param sh_ptr The shared pointer to be copied.
1001  */
1002  template <class U> SharedLockPtr(const SharedLockPtr<U>& sh_ptr) noexcept {
1003  // because we are allowing an implicit cast from derived to
1004  // base class referenced object, we need to assign from each
1005  // member of sh_ptr.ref_items separately
1006 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
1007  ref_items.mutex_p = sh_ptr.ref_items.mutex_p;
1008 #endif
1009  ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p;
1010  ref_items.obj_p = sh_ptr.ref_items.obj_p;
1011  reference();
1012  }
1013 
1014  /**
1015  * A version of the move constructor which enables pointer type
1016  * conversion (assuming the type passed is implicitly type
1017  * convertible to the managed type, such as a derived type). This
1018  * move constructor does not throw.
1019  * @param sh_ptr The shared pointer to be moved.
1020  */
1021  template <class U> SharedLockPtr(SharedLockPtr<U>&& sh_ptr) noexcept {
1022  // because we are allowing an implicit cast from derived to
1023  // base class referenced object, we need to assign from each
1024  // member of sh_ptr.ref_items separately
1025 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
1026  ref_items.mutex_p = sh_ptr.ref_items.mutex_p;
1027 #endif
1028  ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p;
1029  ref_items.obj_p = sh_ptr.ref_items.obj_p;
1030 
1031 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
1032  sh_ptr.ref_items.mutex_p = 0; // make sure the value is valid as we may assign it
1033 #endif
1034  sh_ptr.ref_items.ref_count_p = 0;
1035  sh_ptr.ref_items.obj_p = 0;
1036  }
1037 
1038  /**
1039  * This method (and so copy or move assignment) does not throw unless
1040  * the destructor of a managed object throws.
1041  * @param sh_ptr the assignor.
1042  * @return The SharedLockPtr object after assignment.
1043  */
1044  // having a value type as the argument, rather than reference to const
1045  // and then initialising a tmp object, gives the compiler more scope
1046  // for optimisation, and also caters for r-values without a separate
1047  // overload
1049  std::swap(ref_items, sh_ptr.ref_items);
1050  return *this;
1051  }
1052 
1053  /**
1054  * A version of the assignment operator which enables pointer type
1055  * conversion (assuming the type passed is implicitly type
1056  * convertible to the managed type, such as a derived type). This
1057  * method does not throw unless the destructor of a managed object
1058  * throws.
1059  * @param sh_ptr the assignor.
1060  * @return The SharedLockPtr object after assignment.
1061  */
1062  template <class U> SharedLockPtr& operator=(const SharedLockPtr<U>& sh_ptr) {
1063  return operator=(SharedLockPtr(sh_ptr));
1064  }
1065 
1066  /**
1067  * A version of the operator for move assignment which enables
1068  * pointer type conversion (assuming the type passed is implicitly
1069  * type convertible to the managed type, such as a derived type).
1070  * This method does not throw unless the destructor of a managed
1071  * object throws.
1072  * @param sh_ptr the shared pointer to be moved.
1073  * @return The SharedLockPtr object after the move operation.
1074  */
1075  template <class U> SharedLockPtr& operator=(SharedLockPtr<U>&& sh_ptr) {
1076  return operator=(SharedLockPtr(std::move(sh_ptr)));
1077  }
1078 
1079  /**
1080  * This method does not throw.
1081  * @return A pointer to the managed object (or NULL if none is
1082  * managed).
1083  */
1084  T* get() const noexcept {return ref_items.obj_p;}
1085 
1086  /**
1087  * This method does not throw.
1088  * @return A reference to the managed object.
1089  */
1090  T& operator*() const noexcept {return *ref_items.obj_p;}
1091 
1092  /**
1093  * This method does not throw.
1094  * @return A pointer to the managed object (or NULL if none is
1095  * managed).
1096  */
1097  T* operator->() const noexcept {return ref_items.obj_p;}
1098 
1099  /**
1100  * This method does not throw.
1101  * @return The number of SharedLockPtr objects referencing the
1102  * managed object (or 0 if none is managed by this SharedLockPtr).
1103  * @note The return value may not be valid if another thread has
1104  * changed the reference count before the value returned by this
1105  * method is acted on. It is provided as a utility, but may not be
1106  * meaningful, depending on the intended usage.
1107  */
1108  unsigned int get_refcount() const noexcept {
1109  if (!ref_items.ref_count_p) return 0;
1110 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
1111  Thread::Mutex::Lock lock(*ref_items.mutex_p);
1112  return *ref_items.ref_count_p;
1113 #else
1114  return g_atomic_int_get(ref_items.ref_count_p);
1115 #endif
1116  }
1117 
1118  /**
1119  * The destructor does not throw unless the destructor of a managed
1120  * object throws - that should never happen.
1121  */
1122  ~SharedLockPtr() {unreference();}
1123 };
1124 
1125 #if defined(CGU_USE_SMART_PTR_COMPARISON) || defined(DOXYGEN_PARSING)
1126 
1127 // we can use built-in operator == when comparing pointers referencing
1128 // different objects of the same type
1129 /**
1130  * @ingroup handles
1131  *
1132  * This comparison operator does not throw. It compares the addresses
1133  * of the managed objects.
1134  *
1135  * Since 2.0.0-rc2
1136  */
1137 template <class T>
1138 bool operator==(const SharedPtr<T>& s1, const SharedPtr<T>& s2) noexcept {
1139  return (s1.get() == s2.get());
1140 }
1141 
1142 /**
1143  * @ingroup handles
1144  *
1145  * This comparison operator does not throw. It compares the addresses
1146  * of the managed objects.
1147  *
1148  * Since 2.0.0-rc2
1149  */
1150 template <class T>
1151 bool operator!=(const SharedPtr<T>& s1, const SharedPtr<T>& s2) noexcept {
1152  return !(s1 == s2);
1153 }
1154 
1155 // we must use std::less rather than the < built-in operator for
1156 // pointers to objects not within the same array or object: "For
1157 // templates greater, less, greater_equal, and less_equal, the
1158 // specializations for any pointer type yield a total order, even if
1159 // the built-in operators <, >, <=, >= do not." (para 20.3.3/8).
1160 /**
1161  * @ingroup handles
1162  *
1163  * This comparison operator does not throw unless std::less applied to
1164  * pointer types throws (which it would not do with any sane
1165  * implementation). It compares the addresses of the managed objects.
1166  *
1167  * Since 2.0.0-rc2
1168  */
1169 template <class T>
1170 bool operator<(const SharedPtr<T>& s1, const SharedPtr<T>& s2) {
1171  return std::less<T*>()(s1.get(), s2.get());
1172 }
1173 
1174 /**
1175  * @ingroup handles
1176  *
1177  * This comparison operator does not throw. It compares the addresses
1178  * of the managed objects.
1179  *
1180  * Since 2.0.0-rc2
1181  */
1182 template <class T>
1183 bool operator==(const SharedLockPtr<T>& s1, const SharedLockPtr<T>& s2) noexcept {
1184  return (s1.get() == s2.get());
1185 }
1186 
1187 /**
1188  * @ingroup handles
1189  *
1190  * This comparison operator does not throw. It compares the addresses
1191  * of the managed objects.
1192  *
1193  * Since 2.0.0-rc2
1194  */
1195 template <class T>
1196 bool operator!=(const SharedLockPtr<T>& s1, const SharedLockPtr<T>& s2) noexcept {
1197  return !(s1 == s2);
1198 }
1199 
1200 /**
1201  * @ingroup handles
1202  *
1203  * This comparison operator does not throw unless std::less applied to
1204  * pointer types throws (which it would not do with any sane
1205  * implementation). It compares the addresses of the managed objects.
1206  *
1207  * Since 2.0.0-rc2
1208  */
1209 template <class T>
1210 bool operator<(const SharedLockPtr<T>& s1, const SharedLockPtr<T>& s2) {
1211  return std::less<T*>()(s1.get(), s2.get());
1212 }
1213 
1214 #endif // CGU_USE_SMART_PTR_COMPARISON
1215 
1216 } // namespace Cgu
1217 
1218 // doxygen produces long filenames that tar can't handle:
1219 // we have generic documentation for std::hash specialisations
1220 // in doxygen.main.in
1221 #if defined(CGU_USE_SMART_PTR_COMPARISON) && !defined(DOXYGEN_PARSING)
1222 /* These structs allow SharedPtr and SharedLockPtr objects to be keys
1223  in unordered associative containers */
1224 namespace std {
1225 template <class T>
1226 struct hash<Cgu::SharedPtr<T>> {
1227  typedef std::size_t result_type;
1228  typedef Cgu::SharedPtr<T> argument_type;
1229  result_type operator()(const argument_type& s) const {
1230  // this is fine: std::hash structs do not normally contain data and
1231  // std::hash<T*> certainly won't, so we don't have overhead constructing
1232  // std::hash<T*> on the fly
1233  return std::hash<T*>()(s.get());
1234  }
1235 };
1236 template <class T>
1237 struct hash<Cgu::SharedLockPtr<T>> {
1238  typedef std::size_t result_type;
1239  typedef Cgu::SharedLockPtr<T> argument_type;
1240  result_type operator()(const argument_type& s) const {
1241  // this is fine: std::hash structs do not normally contain data and
1242  // std::hash<T*> certainly won't, so we don't have overhead constructing
1243  // std::hash<T*> on the fly
1244  return std::hash<T*>()(s.get());
1245  }
1246 };
1247 } // namespace std
1248 #endif // CGU_USE_SMART_PTR_COMPARISON
1249 
1250 #endif
Cgu::SharedPtrError
This is an exception struct thrown as an alternative to deleting a managed object when internal memor...
Definition: shared_ptr.h:113
Cgu::SharedLockPtr::get_refcount
unsigned int get_refcount() const noexcept
Definition: shared_ptr.h:1108
Cgu::SharedLockPtr::operator=
SharedLockPtr & operator=(SharedLockPtr sh_ptr)
Definition: shared_ptr.h:1048
Cgu::SharedPtr::operator=
SharedPtr & operator=(const SharedPtr< U > &sh_ptr)
Definition: shared_ptr.h:467
Cgu
Definition: application.h:44
Cgu::Thread::Mutex::lock
int lock() noexcept
Definition: mutex.h:147
Cgu::SharedLockPtr::SharedLockPtr
SharedLockPtr(T *ptr, Cgu::SharedPtrAllocFail::Leave tag)
Definition: shared_ptr.h:824
Cgu::SharedLockPtr::reset
void reset(T *ptr, Cgu::SharedPtrAllocFail::Leave tag)
Definition: shared_ptr.h:966
Cgu::SharedPtr::operator*
T & operator*() const noexcept
Definition: shared_ptr.h:495
Cgu::SharedPtr::reset
void reset(T *ptr, Cgu::SharedPtrAllocFail::Leave tag)
Definition: shared_ptr.h:384
Cgu::SharedLockPtr::SharedLockPtr
SharedLockPtr(SharedLockPtr &&sh_ptr) noexcept
Definition: shared_ptr.h:984
Cgu::SharedPtrAllocFail::leave
@ leave
Definition: shared_ptr.h:129
Cgu::SharedLockPtr::reset
void reset(T *ptr=0)
Definition: shared_ptr.h:910
Cgu::SharedPtrError::obj
T * obj
Definition: shared_ptr.h:114
Cgu::SharedLockPtr::SharedLockPtr
SharedLockPtr(const SharedLockPtr< U > &sh_ptr) noexcept
Definition: shared_ptr.h:1002
Cgu::SharedLockPtr::operator=
SharedLockPtr & operator=(const SharedLockPtr< U > &sh_ptr)
Definition: shared_ptr.h:1062
Cgu::operator<
bool operator<(const GobjHandle< T > &h1, const GobjHandle< T > &h2)
Definition: gobj_handle.h:632
Cgu::operator!=
bool operator!=(const GobjHandle< T > &h1, const GobjHandle< T > &h2) noexcept
Definition: gobj_handle.h:613
Cgu::swap
void swap(Cgu::AsyncQueue< T, Container > &q1, Cgu::AsyncQueue< T, Container > &q2)
Definition: async_queue.h:1493
Cgu::SharedPtr::operator->
T * operator->() const noexcept
Definition: shared_ptr.h:502
Cgu::SharedLockPtr::~SharedLockPtr
~SharedLockPtr()
Definition: shared_ptr.h:1122
Cgu::SharedPtr::operator=
SharedPtr & operator=(SharedPtr sh_ptr)
Definition: shared_ptr.h:453
Cgu::SharedPtr::SharedPtr
SharedPtr(const SharedPtr< U > &sh_ptr) noexcept
Definition: shared_ptr.h:417
Cgu::SharedLockPtr::operator=
SharedLockPtr & operator=(SharedLockPtr< U > &&sh_ptr)
Definition: shared_ptr.h:1075
Cgu::SharedLockPtr::get
T * get() const noexcept
Definition: shared_ptr.h:1084
Cgu::SharedPtr
This is a smart pointer for managing the lifetime of objects allocated on freestore.
Definition: shared_ptr.h:211
Cgu::SharedPtrAllocFail::Leave
Leave
Definition: shared_ptr.h:129
Cgu::SharedLockPtr::operator->
T * operator->() const noexcept
Definition: shared_ptr.h:1097
Cgu::SharedPtr::SharedPtr
SharedPtr(SharedPtr< U > &&sh_ptr) noexcept
Definition: shared_ptr.h:433
Cgu::SharedPtr::reset
void reset(T *ptr=0)
Definition: shared_ptr.h:346
Cgu::SharedPtr::SharedPtr
SharedPtr(T *ptr=0)
Definition: shared_ptr.h:256
Cgu::SharedPtr::operator=
SharedPtr & operator=(SharedPtr< U > &&sh_ptr)
Definition: shared_ptr.h:480
Cgu::operator==
bool operator==(const GobjHandle< T > &h1, const GobjHandle< T > &h2) noexcept
Definition: gobj_handle.h:600
Cgu::SharedPtr::~SharedPtr
~SharedPtr()
Definition: shared_ptr.h:515
Cgu::SharedPtrError::what
virtual const char * what() const
Definition: shared_ptr.h:115
Cgu::Thread::Mutex::Lock
A scoped locking class for exception safe Mutex locking.
Definition: mutex.h:207
hash
A specialization of std::hash for Cgu::Callback::FunctorArg, Cgu::Callback::SafeFunctorArg,...
Cgu::SharedLockPtr::SharedLockPtr
friend class SharedLockPtr
Definition: shared_ptr.h:993
Cgu::SharedLockPtr::SharedLockPtr
SharedLockPtr(T *ptr=0)
Definition: shared_ptr.h:736
Cgu::SharedPtr::SharedPtr
SharedPtr(T *ptr, Cgu::SharedPtrAllocFail::Leave tag)
Definition: shared_ptr.h:304
mutex.h
Provides wrapper classes for pthread mutexes and condition variables, and scoped locking classes for ...
Cgu::SharedLockPtr
This is a smart pointer for managing the lifetime of objects allocated on freestore,...
Definition: shared_ptr.h:644
Cgu::SharedLockPtr::SharedLockPtr
SharedLockPtr(const SharedLockPtr &sh_ptr) noexcept
Definition: shared_ptr.h:975
Cgu::SharedPtr::SharedPtr
friend class SharedPtr
Definition: shared_ptr.h:408
Cgu::SharedPtr::get_refcount
unsigned int get_refcount() const noexcept
Definition: shared_ptr.h:509
Cgu::SharedLockPtr::operator*
T & operator*() const noexcept
Definition: shared_ptr.h:1090
Cgu::Thread::MutexError
Definition: mutex.h:81
Cgu::Thread::Mutex
A wrapper class for pthread mutexes.
Definition: mutex.h:117
cgu_config.h
Cgu::SharedPtr::SharedPtr
SharedPtr(const SharedPtr &sh_ptr) noexcept
Definition: shared_ptr.h:393
Cgu::SharedPtrError::SharedPtrError
SharedPtrError(T *p)
Definition: shared_ptr.h:116
Cgu::SharedLockPtr::SharedLockPtr
SharedLockPtr(SharedLockPtr< U > &&sh_ptr) noexcept
Definition: shared_ptr.h:1021
Cgu::SharedPtr::SharedPtr
SharedPtr(SharedPtr &&sh_ptr) noexcept
Definition: shared_ptr.h:402
Cgu::SharedPtr::get
T * get() const noexcept
Definition: shared_ptr.h:489