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