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