c++-gtk-utils
shared_ptr.h
Go to the documentation of this file.
1 /* Copyright (C) 2004 to 2013 Chris Vine
2 
3 The library comprised in this file or of which this file is part is
4 distributed by Chris Vine under the GNU Lesser General Public
5 License as follows:
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public License
9  as published by the Free Software Foundation; either version 2.1 of
10  the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License, version 2.1, for more details.
16 
17  You should have received a copy of the GNU Lesser General Public
18  License, version 2.1, along with this library (see the file LGPL.TXT
19  which came with this source code package in the c++-gtk-utils
20  sub-directory); if not, write to the Free Software Foundation, Inc.,
21  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 
23 However, it is not intended that the object code of a program whose
24 source code instantiates a template from this file or uses macros or
25 inline functions (of any length) should by reason only of that
26 instantiation or use be subject to the restrictions of use in the GNU
27 Lesser General Public License. With that in mind, the words "and
28 macros, inline functions and instantiations of templates (of any
29 length)" shall be treated as substituted for the words "and small
30 macros and small inline functions (ten lines or less in length)" in
31 the fourth paragraph of section 5 of that licence. This does not
32 affect any other reason why object code may be subject to the
33 restrictions in that licence (nor for the avoidance of doubt does it
34 affect the application of section 2 of that licence to modifications
35 of the source code in this file).
36 
37 */
38 
39 #ifndef CGU_SHARED_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 in C++11, but this class is retained in the
149  * c++-gtk-utils library not only to retain compatibility with series
150  * 1.2 of the library, but also to cater for some cases not met (or
151  * 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 C++11's 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() {
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) {
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) {
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) {
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) {
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 {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 {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 {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 {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  * If that is the case, a mutex for the referenced object will
554  * also be required when reading any given instance of such an
555  * object in more than one thread by dereferencing any shared
556  * pointers referencing it (and indeed, when not using shared
557  * pointers at all).
558  *
559  * As mentioned, by default glib atomic functions are used to provide
560  * thread-safe manipulation of the reference count. However, the
561  * symbol CGU_SHARED_LOCK_PTR_USE_MUTEX can be defined so that the
562  * library uses mutexes instead, which might be useful for some
563  * debugging purposes. Note that if CGU_SHARED_LOCK_PTR_USE_MUTEX is
564  * to be defined, this is best done by textually amending the
565  * shared_ptr.h header file before the library is compiled. This will
566  * ensure that everything in the program and the library which
567  * includes the shared_ptr.h header is guaranteed to see the same
568  * definitions so that the C++ standard's one-definition-rule is
569  * complied with.
570  *
571  * @b Comparison @b with @b std::shared_ptr
572  *
573  * Most of the things that can be done by this class can be done by
574  * using std::shared_ptr in C++11, but this class is retained in the
575  * c++-gtk-utils library not only to retain compatibility with series
576  * 1.2 of the library, but also to cater for some cases not met (or
577  * not so easily met) by std::shared_ptr:
578  *
579  * 1. Glib memory slices provide an efficient small object allocator
580  * (they are likely to be significantly more efficient than global
581  * operator new()/new[](), which generally hand off to malloc(),
582  * and whilst malloc() is good for large block allocations it is
583  * generally poor as a small object allocator). Internal
584  * Cgu::SharedLockPtr allocation using glib memory slices can be
585  * achieved by compiling the library with the
586  * \--with-glib-memory-slices-no-compat configuration option.
587  * 2. If glib memory slices are not used (which do not throw),
588  * constructing a shared pointer for a new managed object (or
589  * calling reset() for a new managed object) might throw if
590  * internal allocation fails. Although by default the
591  * Cgu::SharedLockPtr implementation will delete the new managed
592  * object in such a case, it also provides an alternative
593  * constructor and reset() method which instead enable the new
594  * object to be accessed via the thrown exception object so that
595  * user code can decide what to do; std::shared_ptr deletes the new
596  * object in every case.
597  * 3. A user can explicitly state whether the shared pointer object is
598  * to have atomic increment and decrement-and-test with respect to
599  * the reference count so that the reference count is thread safe
600  * ('no' in the case of Cgu::SharedPtr, and 'yes' in the case of
601  * Cgu::SharedLockPtr). Using atomic functions is unnecessary if
602  * the managed object concerned is only addressed in one thread
603  * (and might cause unwanted cache flushing in certain
604  * circumstances). std::shared_ptr will generally always use
605  * atomic functions with respect to its reference count in a
606  * multi-threaded program.
607  *
608  * In favour of C++11's std::shared_ptr, it has an associated
609  * std::make_shared() factory function which will construct both the
610  * referenced object and the shared pointer's reference count within a
611  * single memory block when the first shared pointer managing a
612  * particular object is constructed. Cgu::SharedPtr and
613  * Cgu::SharedLockPtr always allocate these separately, but this is
614  * partly mitigated by the use of glib memory slices to allocate the
615  * reference count where the \--with-glib-memory-slices-no-compat
616  * configuration option is chosen.
617  *
618  * In addition, std::shared_ptr has an associated std::weak_ptr class,
619  * which Cgu::SharedLockPtr does not (there is a Cgu::GobjWeakHandle
620  * class, but that is cognate with Cgu::GobjHandle and is only usable
621  * with GObjects), and shared_ptr objects also have some atomic store,
622  * load and exchange functions provided for them which enable
623  * concurrent modifications of the same instance of shared_ptr in
624  * different threads to have defined results.
625  *
626  * If the library is compiled with the
627  * \--with-glib-memory-slices-no-compat configuration option, as
628  * mentioned Cgu::SharedLockPtr constructs its reference counting
629  * internals using glib memory slices. Although it is safe in a
630  * multi-threaded program if glib < 2.32 is installed to construct a
631  * static SharedLockPtr object in global namespace (that is, prior to
632  * g_thread_init() being called) by means of the default constructor
633  * and/or a pointer argument of NULL, it is not safe if constructed
634  * with a non-NULL pointer value. If glib >= 2.32 is installed,
635  * global objects with memory slices are safe in all
636  * circumstances. (Having said that, it would be highly unusual to
637  * have global SharedLockPtr objects.)
638  */
639 
640 template <class T> class SharedLockPtr {
641 
642 #ifndef DOXYGEN_PARSING
643  struct RefItems {
644 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
645  Thread::Mutex* mutex_p;
646  unsigned int* ref_count_p;
647 #else
648  gint* ref_count_p;
649 #endif
650  T* obj_p;
651  } ref_items;
652 #endif
653 
654  // SharedLockPtr<T>::unreference() does not throw if the destructor of the
655  // contained object does not throw, because Thread::Mutex::~Mutex(),
656  // Thread::Mutex::lock() and Thread::Mutex::unlock() do not throw
657  void unreference() {
658  // we can (and should) check whether ref_items.ref_count_p is NULL without
659  // a lock, because that member is specific to this SharedLockPtr object.
660  // Only the integer pointed to by it is shared amongst SharedLockPtr
661  // objects and requires locking
662  if (!ref_items.ref_count_p) return;
663 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
664  ref_items.mutex_p->lock();
665  --(*ref_items.ref_count_p);
666  if (*ref_items.ref_count_p == 0) {
667 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
668  g_slice_free(unsigned int, ref_items.ref_count_p);
669 # else
670  delete ref_items.ref_count_p;
671 # endif
672  ref_items.mutex_p->unlock();
673  delete ref_items.mutex_p;
674  delete ref_items.obj_p;
675  }
676  else ref_items.mutex_p->unlock();
677 #else
678  if (g_atomic_int_dec_and_test(ref_items.ref_count_p)) {
679 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
680  g_slice_free(gint, ref_items.ref_count_p);
681 # else
682  delete ref_items.ref_count_p;
683 # endif
684  delete ref_items.obj_p;
685  }
686 #endif
687  }
688 
689  // SharedLockPtr<T>::reference() does not throw because
690  // Thread::Mutex::Lock::Lock() and Thread::Mutex::Lock::~Lock() do not throw
691  void reference() {
692  // we can (and should) check whether ref_items.ref_count_p is NULL without
693  // a lock, because that member is specific to this SharedLockPtr object.
694  // Only the integer pointed to by it is shared amongst SharedLockPtr
695  // objects and requires locking
696  if (!ref_items.ref_count_p) return;
697 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
698  Thread::Mutex::Lock lock(*ref_items.mutex_p);
699  ++(*ref_items.ref_count_p);
700 #else
701  g_atomic_int_inc(ref_items.ref_count_p);
702 #endif
703  }
704 
705 public:
706 /**
707  * Constructor taking an unmanaged object.
708  * @param ptr The object which the SharedLockPtr is to manage (if
709  * any).
710  * @exception std::bad_alloc This constructor will not throw if the
711  * 'ptr' argument has a NULL value (the default), otherwise it might
712  * throw std::bad_alloc if memory is exhausted and the system throws
713  * in that case. If such an exception is thrown, this constructor is
714  * exception safe (it does not leak resources), but as well as
715  * cleaning itself up this constructor will also delete the managed
716  * object passed to it to avoid a memory leak. If such automatic
717  * deletion is not wanted in that case, use the version of this
718  * constructor taking a Cgu::SharedPtrAllocFail::Leave tag argument.
719  * @note 1. std::bad_alloc will not be thrown if the library has been
720  * installed using the \--with-glib-memory-slices-no-compat
721  * configuration option: instead glib will terminate the program if it
722  * is unable to obtain memory from the operating system.
723  * @note 2. By default, glib atomic functions are used to provide
724  * thread-safe manipulation of the reference count. However, the
725  * header file shared_ptr.h can be textually amended before the
726  * library is compiled to define the symbol
727  * CGU_SHARED_LOCK_PTR_USE_MUTEX so as to use mutexes instead, which
728  * might be useful for some debugging purposes. Were that to be done,
729  * Cgu::Thread::MutexError might be thrown by this constructor if
730  * initialization of the mutex fails.
731  */
732  explicit SharedLockPtr(T* ptr = 0) {
733 
734  if ((ref_items.obj_p = ptr)) { // not NULL
735 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
736  try {
737  ref_items.mutex_p = new Thread::Mutex;
738  }
739  catch (...) {
740  delete ptr; // if allocating the object referenced by ref_items.mutex_p
741  // has failed then delete the object to be referenced to
742  // avoid a memory leak
743  throw;
744  }
745 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
746  ref_items.ref_count_p = g_slice_new(unsigned int);
747  *ref_items.ref_count_p = 1;
748 # else
749  try {
750  ref_items.ref_count_p = new unsigned int(1);
751  }
752  catch (...) {
753  delete ref_items.mutex_p;
754  delete ptr;
755  throw;
756  }
757 # endif
758 #else
759 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
760  ref_items.ref_count_p = g_slice_new(gint);
761  *ref_items.ref_count_p = 1;
762 # else
763  try {
764  ref_items.ref_count_p = new gint(1);
765  }
766  catch (...) {
767  delete ptr; // if allocating the int referenced by ref_items.ref_count_p
768  // has failed then delete the object to be referenced to
769  // avoid a memory leak
770  throw;
771  }
772 # endif
773 #endif
774  }
775  else {
776 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
777  ref_items.mutex_p = 0; // make sure the value is valid as we may assign it
778 #endif
779  ref_items.ref_count_p = 0;
780  }
781  }
782 
783 /**
784  * Constructor taking an unmanaged object.
785  * @param ptr The object which the SharedLockPtr is to manage.
786  * @param tag Passing the tag emumerator
787  * Cgu::SharedPtrAllocFail::leave causes this constructor not to
788  * delete the new managed object passed as the 'ptr' argument in the
789  * event of internal allocation in this method failing because of
790  * memory exhaustion (in that event, Cgu::SharedPtrError will be
791  * thrown).
792  * @exception Cgu::SharedPtrError This constructor might throw
793  * Cgu::SharedPtrError if memory is exhausted and the system would
794  * otherwise throw std::bad_alloc in that case. This constructor is
795  * exception safe (it does not leak resources), and if such an
796  * exception is thrown it will clean itself up, but it will not
797  * attempt to delete the new managed object passed to it. Access to
798  * the object passed to the 'ptr' argument can be obtained via the
799  * thrown Cgu::SharedPtrError object.
800  * @note 1. On systems with over-commit/lazy-commit combined with
801  * virtual memory (swap), it is rarely useful to check for memory
802  * exhaustion, so in those cases this version of the constructor will
803  * not be useful.
804  * @note 2. If the library has been installed using the
805  * \--with-glib-memory-slices-no-compat configuration option this
806  * version of the constructor will also not be useful: instead glib
807  * will terminate the program if it is unable to obtain memory from
808  * the operating system.
809  * @note 3. By default, glib atomic functions are used to provide
810  * thread-safe manipulation of the reference count. However, the
811  * header file shared_ptr.h can be textually amended before the
812  * library is compiled to define the symbol
813  * CGU_SHARED_LOCK_PTR_USE_MUTEX so as to use mutexes instead, which
814  * might be useful for some debugging purposes. Were that to be done,
815  * Cgu::SharedPtrError might be thrown by this constructor if
816  * initialization of the mutex fails (even if the
817  * \--with-glib-memory-slices-no-compat configuration option is
818  * chosen).
819  */
821 
822  if ((ref_items.obj_p = ptr)) { // not NULL
823 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
824  try {
825  ref_items.mutex_p = new Thread::Mutex;
826  }
827  catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly
828  throw SharedPtrError<T>(ptr);
829  }
830  catch (Thread::MutexError&) { // as we are not rethrowing, make NPTL friendly
831  throw SharedPtrError<T>(ptr);
832  }
833 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
834  ref_items.ref_count_p = g_slice_new(unsigned int);
835  *ref_items.ref_count_p = 1;
836 # else
837  try {
838  ref_items.ref_count_p = new unsigned int(1);
839  }
840  catch (std::bad_alloc&) {
841  delete ref_items.mutex_p;
842  throw SharedPtrError<T>(ptr);
843  }
844 # endif
845 #else
846 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
847  ref_items.ref_count_p = g_slice_new(gint);
848  *ref_items.ref_count_p = 1;
849 # else
850  try {
851  ref_items.ref_count_p = new gint(1);
852  }
853  catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly
854  throw SharedPtrError<T>(ptr);
855  }
856 # endif
857 #endif
858  }
859  else {
860 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
861  ref_items.mutex_p = 0; // make sure the value is valid as we may assign it
862 #endif
863  ref_items.ref_count_p = 0;
864  }
865  }
866 
867 /**
868  * Causes the SharedLockPtr to cease to manage its managed object (if
869  * any), deleting it if this is the last SharedLockPtr object managing
870  * it. If the argument passed is not NULL, the SharedLockPtr object
871  * will manage the new object passed (which must not be managed by any
872  * other SharedLockPtr object). This method is exception safe, but
873  * see the comments below on std::bad_alloc.
874  * @param ptr NULL (the default), or a new unmanaged object to manage.
875  * @exception std::bad_alloc This method will not throw if the 'ptr'
876  * argument has a NULL value (the default) and the destructor of a
877  * managed object does not throw, otherwise it might throw
878  * std::bad_alloc if memory is exhausted and the system throws in that
879  * case. Note that if such an exception is thrown then this method
880  * will do nothing (it is strongly exception safe and will continue to
881  * manage the object it was managing prior to the call), except that
882  * it will delete the new managed object passed to it to avoid a
883  * memory leak. If such automatic deletion in the event of such an
884  * exception is not wanted, use the reset() method taking a
885  * Cgu::SharedPtrAllocFail::Leave tag type as its second argument.
886  * @note 1. std::bad_alloc will not be thrown if the library has been
887  * installed using the \--with-glib-memory-slices-no-compat
888  * configuration option: instead glib will terminate the program if it
889  * is unable to obtain memory from the operating system.
890  * @note 2. By default, glib atomic functions are used to provide
891  * thread-safe manipulation of the reference count. However, the
892  * header file shared_ptr.h can be textually amended before the
893  * library is compiled to define the symbol
894  * CGU_SHARED_LOCK_PTR_USE_MUTEX so as to use mutexes instead, which
895  * might be useful for some debugging purposes. Were that to be done,
896  * Cgu::Thread::MutexError might be thrown by this method if
897  * initialization of the mutex fails.
898  * @note 3. A SharedLockPtr object protects its reference count but
899  * not the managed object or its other internals. The reset() method
900  * should not be called by one thread in respect of a particular
901  * SharedLockPtr object while another thread may be operating on,
902  * copying or dereferencing the same instance of SharedLockPtr. It is
903  * thread-safe as against another instance of SharedLockPtr managing
904  * the same object.
905  */
906  void reset(T* ptr = 0) {
907  SharedLockPtr tmp(ptr);
908  std::swap(ref_items, tmp.ref_items);
909  }
910 
911 /**
912  * Causes the SharedLockPtr to cease to manage its managed object (if
913  * any), deleting it if this is the last SharedLockPtr object managing
914  * it. The SharedLockPtr object will manage the new object passed
915  * (which must not be managed by any other SharedLockPtr object).
916  * This method is exception safe, but see the comments below on
917  * Cgu::SharedPtrError.
918  * @param ptr A new unmanaged object to manage (if no new object is to
919  * be managed, use the version of reset() taking a default value of
920  * NULL).
921  * @param tag Passing the tag emumerator
922  * Cgu::SharedPtrAllocFail::leave causes this method not to delete the
923  * new managed object passed as the 'ptr' argument in the event of
924  * internal allocation in this method failing because of memory
925  * exhaustion (in that event, Cgu::SharedPtrError will be thrown).
926  * @exception Cgu::SharedPtrError This method might throw
927  * Cgu::SharedPtrError if memory is exhausted and the system would
928  * otherwise throw std::bad_alloc in that case. Note that if such an
929  * exception is thrown then this method will do nothing (it is
930  * strongly exception safe and will continue to manage the object it
931  * was managing prior to the call), and it will not attempt to delete
932  * the new managed object passed to it. Access to the object passed
933  * to the 'ptr' argument can be obtained via the thrown
934  * Cgu::SharedPtrError object.
935  * @note 1. A SharedLockPtr object protects its reference count but
936  * not the managed object or its other internals. The reset() method
937  * should not be called by one thread in respect of a particular
938  * SharedLockPtr object while another thread may be operating on,
939  * copying or dereferencing the same instance of SharedLockPtr. It is
940  * thread-safe as against another instance of SharedLockPtr managing
941  * the same object.
942  * @note 2. On systems with over-commit/lazy-commit combined with
943  * virtual memory (swap), it is rarely useful to check for memory
944  * exhaustion, so in those cases this version of the reset() method
945  * will not be useful.
946  * @note 3. If the library has been installed using the
947  * \--with-glib-memory-slices-no-compat configuration option this
948  * version of the reset() method will also not be useful: instead glib
949  * will terminate the program if it is unable to obtain memory from
950  * the operating system.
951  * @note 4. By default, glib atomic functions are used to provide
952  * thread-safe manipulation of the reference count. However, the
953  * header file shared_ptr.h can be textually amended before the
954  * library is compiled to define the symbol
955  * CGU_SHARED_LOCK_PTR_USE_MUTEX so as to use mutexes instead, which
956  * might be useful for some debugging purposes. Were that to be done,
957  * Cgu::SharedPtrError might be thrown by this method if
958  * initialization of the mutex fails (even if the
959  * \--with-glib-memory-slices-no-compat configuration option is
960  * chosen).
961  */
963  SharedLockPtr tmp(ptr, tag);
964  std::swap(ref_items, tmp.ref_items);
965  }
966 
967  /**
968  * This copy constructor does not throw.
969  * @param sh_ptr The shared pointer to be copied.
970  */
971  SharedLockPtr(const SharedLockPtr& sh_ptr) {
972  ref_items = sh_ptr.ref_items;
973  reference();
974  }
975 
976  /**
977  * The move constructor does not throw. It has move semantics.
978  * @param sh_ptr The shared pointer to be moved.
979  */
981  ref_items = sh_ptr.ref_items;
982 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
983  sh_ptr.ref_items.mutex_p = 0; // make sure the value is valid as we may assign it
984 #endif
985  sh_ptr.ref_items.ref_count_p = 0;
986  sh_ptr.ref_items.obj_p = 0;
987  }
988 
989  template <class U> friend class SharedLockPtr;
990 
991  /**
992  * A version of the copy constructor which enables pointer type
993  * conversion (assuming the type passed is implicitly type
994  * convertible to the managed type, such as a derived type). This
995  * copy constructor does not throw.
996  * @param sh_ptr The shared pointer to be copied.
997  */
998  template <class U> SharedLockPtr(const SharedLockPtr<U>& sh_ptr) {
999  // because we are allowing an implicit cast from derived to
1000  // base class referenced object, we need to assign from each
1001  // member of sh_ptr.ref_items separately
1002 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
1003  ref_items.mutex_p = sh_ptr.ref_items.mutex_p;
1004 #endif
1005  ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p;
1006  ref_items.obj_p = sh_ptr.ref_items.obj_p;
1007  reference();
1008  }
1009 
1010  /**
1011  * A version of the move constructor which enables pointer type
1012  * conversion (assuming the type passed is implicitly type
1013  * convertible to the managed type, such as a derived type). This
1014  * move constructor does not throw.
1015  * @param sh_ptr The shared pointer to be moved.
1016  */
1017  template <class U> SharedLockPtr(SharedLockPtr<U>&& sh_ptr) {
1018  // because we are allowing an implicit cast from derived to
1019  // base class referenced object, we need to assign from each
1020  // member of sh_ptr.ref_items separately
1021 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
1022  ref_items.mutex_p = sh_ptr.ref_items.mutex_p;
1023 #endif
1024  ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p;
1025  ref_items.obj_p = sh_ptr.ref_items.obj_p;
1026 
1027 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
1028  sh_ptr.ref_items.mutex_p = 0; // make sure the value is valid as we may assign it
1029 #endif
1030  sh_ptr.ref_items.ref_count_p = 0;
1031  sh_ptr.ref_items.obj_p = 0;
1032  }
1033 
1034  /**
1035  * This method (and so copy or move assignment) does not throw unless
1036  * the destructor of a managed object throws.
1037  * @param sh_ptr the assignor.
1038  * @return The SharedLockPtr object after assignment.
1039  */
1040  // having a value type as the argument, rather than reference to const
1041  // and then initialising a tmp object, gives the compiler more scope
1042  // for optimisation, and also caters for r-values without a separate
1043  // overload
1045  std::swap(ref_items, sh_ptr.ref_items);
1046  return *this;
1047  }
1048 
1049  /**
1050  * A version of the assignment operator which enables pointer type
1051  * conversion (assuming the type passed is implicitly type
1052  * convertible to the managed type, such as a derived type). This
1053  * method does not throw unless the destructor of a managed object
1054  * throws.
1055  * @param sh_ptr the assignor.
1056  * @return The SharedLockPtr object after assignment.
1057  */
1058  template <class U> SharedLockPtr& operator=(const SharedLockPtr<U>& sh_ptr) {
1059  return operator=(SharedLockPtr(sh_ptr));
1060  }
1061 
1062  /**
1063  * A version of the operator for move assignment which enables
1064  * pointer type conversion (assuming the type passed is implicitly
1065  * type convertible to the managed type, such as a derived type).
1066  * This method does not throw unless the destructor of a managed
1067  * object throws.
1068  * @param sh_ptr the shared pointer to be moved.
1069  * @return The SharedLockPtr object after the move operation.
1070  */
1071  template <class U> SharedLockPtr& operator=(SharedLockPtr<U>&& sh_ptr) {
1072  return operator=(SharedLockPtr(std::move(sh_ptr)));
1073  }
1074 
1075  /**
1076  * This method does not throw.
1077  * @return A pointer to the managed object (or NULL if none is
1078  * managed).
1079  */
1080  T* get() const {return ref_items.obj_p;}
1081 
1082  /**
1083  * This method does not throw.
1084  * @return A reference to the managed object.
1085  */
1086  T& operator*() const {return *ref_items.obj_p;}
1087 
1088  /**
1089  * This method does not throw.
1090  * @return A pointer to the managed object (or NULL if none is
1091  * managed).
1092  */
1093  T* operator->() const {return ref_items.obj_p;}
1094 
1095  /**
1096  * This method does not throw.
1097  * @return The number of SharedLockPtr objects referencing the
1098  * managed object (or 0 if none is managed by this SharedLockPtr).
1099  * @note The return value may not be valid if another thread has
1100  * changed the reference count before the value returned by this
1101  * method is acted on. It is provided as a utility, but may not be
1102  * meaningful, depending on the intended usage.
1103  */
1104  unsigned int get_refcount() const {
1105  if (!ref_items.ref_count_p) return 0;
1106 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
1107  Thread::Mutex::Lock lock(*ref_items.mutex_p);
1108  return *ref_items.ref_count_p;
1109 #else
1110  return g_atomic_int_get(ref_items.ref_count_p);
1111 #endif
1112  }
1113 
1114  /**
1115  * The destructor does not throw unless the destructor of a managed
1116  * object throws - that should never happen.
1117  */
1118  ~SharedLockPtr() {unreference();}
1119 };
1120 
1121 #if defined(CGU_USE_SMART_PTR_COMPARISON) || defined(DOXYGEN_PARSING)
1122 
1123 // we can use built-in operator == when comparing pointers referencing
1124 // different objects of the same type
1125 /**
1126  * @ingroup handles
1127  *
1128  * This comparison operator does not throw. It compares the addresses
1129  * of the managed objects.
1130  *
1131  * Since 2.0.0-rc2
1132  */
1133 template <class T>
1134 bool operator==(const SharedPtr<T>& s1, const SharedPtr<T>& s2) {
1135  return (s1.get() == s2.get());
1136 }
1137 
1138 /**
1139  * @ingroup handles
1140  *
1141  * This comparison operator does not throw. It compares the addresses
1142  * of the managed objects.
1143  *
1144  * Since 2.0.0-rc2
1145  */
1146 template <class T>
1147 bool operator!=(const SharedPtr<T>& s1, const SharedPtr<T>& s2) {
1148  return !(s1 == s2);
1149 }
1150 
1151 // we must use std::less rather than the < built-in operator for
1152 // pointers to objects not within the same array or object: "For
1153 // templates greater, less, greater_equal, and less_equal, the
1154 // specializations for any pointer type yield a total order, even if
1155 // the built-in operators <, >, <=, >= do not." (para 20.3.3/8).
1156 /**
1157  * @ingroup handles
1158  *
1159  * This comparison operator does not throw. It compares the addresses
1160  * of the managed objects.
1161  *
1162  * Since 2.0.0-rc2
1163  */
1164 template <class T>
1165 bool operator<(const SharedPtr<T>& s1, const SharedPtr<T>& s2) {
1166  return std::less<T*>()(s1.get(), s2.get());
1167 }
1168 
1169 /**
1170  * @ingroup handles
1171  *
1172  * This comparison operator does not throw. It compares the addresses
1173  * of the managed objects.
1174  *
1175  * Since 2.0.0-rc2
1176  */
1177 template <class T>
1178 bool operator==(const SharedLockPtr<T>& s1, const SharedLockPtr<T>& s2) {
1179  return (s1.get() == s2.get());
1180 }
1181 
1182 /**
1183  * @ingroup handles
1184  *
1185  * This comparison operator does not throw. It compares the addresses
1186  * of the managed objects.
1187  *
1188  * Since 2.0.0-rc2
1189  */
1190 template <class T>
1191 bool operator!=(const SharedLockPtr<T>& s1, const SharedLockPtr<T>& s2) {
1192  return !(s1 == s2);
1193 }
1194 
1195 /**
1196  * @ingroup handles
1197  *
1198  * This comparison operator does not throw. It compares the addresses
1199  * of the managed objects.
1200  *
1201  * Since 2.0.0-rc2
1202  */
1203 template <class T>
1204 bool operator<(const SharedLockPtr<T>& s1, const SharedLockPtr<T>& s2) {
1205  return std::less<T*>()(s1.get(), s2.get());
1206 }
1207 
1208 #endif // CGU_USE_SMART_PTR_COMPARISON
1209 
1210 } // namespace Cgu
1211 
1212 // doxygen produces long filenames that tar can't handle:
1213 // we have generic documentation for std::hash specialisations
1214 // in doxygen.main.in
1215 #if defined(CGU_USE_SMART_PTR_COMPARISON) && !defined(DOXYGEN_PARSING)
1216 /* These structs allow SharedPtr and SharedLockPtr objects to be keys
1217  in unordered associative containers */
1218 namespace std {
1219 template <class T>
1220 struct hash<Cgu::SharedPtr<T>> {
1221  typedef std::size_t result_type;
1222  typedef Cgu::SharedPtr<T> argument_type;
1223  result_type operator()(const argument_type& s) const {
1224  // this is fine: std::hash structs do not normally contain data and
1225  // std::hash<T*> certainly won't, so we don't have overhead constructing
1226  // std::hash<T*> on the fly
1227  return std::hash<T*>()(s.get());
1228  }
1229 };
1230 template <class T>
1231 struct hash<Cgu::SharedLockPtr<T>> {
1232  typedef std::size_t result_type;
1233  typedef Cgu::SharedLockPtr<T> argument_type;
1234  result_type operator()(const argument_type& s) const {
1235  // this is fine: std::hash structs do not normally contain data and
1236  // std::hash<T*> certainly won't, so we don't have overhead constructing
1237  // std::hash<T*> on the fly
1238  return std::hash<T*>()(s.get());
1239  }
1240 };
1241 } // namespace std
1242 #endif // CGU_USE_SMART_PTR_COMPARISON
1243 
1244 #endif