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 <exception>
48 #include <new>
49 #include <functional> // for std::less
50 #include <algorithm> // for std::swap (c++98)
51 #include <utility> // for std::swap (c++11)
52 
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  * From version 1.2.12, the library provides ==, != and < comparison
146  * operators for SharedPtr, but only if the library is compiled with
147  * the \--with-smart-ptr-comp option, or if the user code defines the
148  * symbol CGU_USE_SMART_PTR_COMPARISON before shared_ptr.h is first
149  * parsed. This is because, if user code has provided such operators
150  * for these smart pointers itself, a duplicated function definition
151  * would arise.
152  *
153  * If the library is compiled with the
154  * \--with-glib-memory-slices-no-compat configuration option,
155  * Cgu::SharedPtr constructs its reference counting internals using
156  * glib memory slices. Although it is safe in a multi-threaded
157  * program if glib < 2.32 is installed to construct a static SharedPtr
158  * object in global namespace (that is, prior to g_thread_init() being
159  * called) by means of the default constructor and/or a pointer
160  * argument of NULL, it is not safe if constructed with a non-NULL
161  * pointer value. If glib >= 2.32 is installed, global objects with
162  * memory slices are safe in all circumstances. (Having said that, it
163  * would be highly unusual to have global SharedPtr objects.)
164  */
165 
166 template <class T> class SharedPtr {
167 
168 #ifndef DOXYGEN_PARSING
169  struct RefItems {
170  unsigned int* ref_count_p;
171  T* obj_p;
172  } ref_items;
173 #endif
174 
175  void unreference() {
176  if (!ref_items.ref_count_p) return;
177  --(*ref_items.ref_count_p);
178  if (*ref_items.ref_count_p == 0) {
179 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
180  g_slice_free(unsigned int, ref_items.ref_count_p);
181 #else
182  delete ref_items.ref_count_p;
183 #endif
184  delete ref_items.obj_p;
185  }
186  }
187 
188  void reference() {
189  if (!ref_items.ref_count_p) return;
190  ++(*ref_items.ref_count_p);
191  }
192 
193 public:
194 /**
195  * Constructor taking an unmanaged object.
196  * @param ptr The object which the SharedPtr is to manage (if any).
197  * @exception std::bad_alloc This constructor will not throw if the
198  * 'ptr' argument has a NULL value (the default), otherwise it might
199  * throw std::bad_alloc if memory is exhausted and the system throws
200  * in that case. If such an exception is thrown, this constructor is
201  * exception safe (it does not leak resources), but as well as
202  * cleaning itself up this constructor will also delete the managed
203  * object passed to it to avoid a memory leak. If such automatic
204  * deletion is not wanted in that case, use the version of this
205  * constructor taking a Cgu::SharedPtrAllocFail::Leave tag argument.
206  * @note std::bad_alloc will not be thrown if the library has been
207  * installed using the \--with-glib-memory-slices-no-compat
208  * configuration option: instead glib will terminate the program if it
209  * is unable to obtain memory from the operating system.
210  */
211  explicit SharedPtr(T* ptr = 0) {
212 
213  if ((ref_items.obj_p = ptr)) { // not NULL
214 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
215  ref_items.ref_count_p = g_slice_new(unsigned int);
216  *ref_items.ref_count_p = 1;
217 #else
218  try {
219  ref_items.ref_count_p = new unsigned int(1);
220  }
221  catch (...) {
222  delete ptr; // if allocating the int referenced by ref_items.ref_count_p
223  // has failed then delete the object to be referenced to
224  // avoid a memory leak
225  throw;
226  }
227 #endif
228  }
229  else ref_items.ref_count_p = 0;
230  }
231 
232 /**
233  * Constructor taking an unmanaged object.
234  * @param ptr The object which the SharedPtr is to manage.
235  * @param tag Passing the tag emumerator
236  * Cgu::SharedPtrAllocFail::leave causes this constructor not to
237  * delete the new managed object passed as the 'ptr' argument in the
238  * event of internal allocation in this method failing because of
239  * memory exhaustion (in that event, Cgu::SharedPtrError will be
240  * thrown).
241  * @exception Cgu::SharedPtrError This constructor might throw
242  * Cgu::SharedPtrError if memory is exhausted and the system would
243  * otherwise throw std::bad_alloc in that case. This constructor is
244  * exception safe (it does not leak resources), and if such an
245  * exception is thrown it will clean itself up, but it will not
246  * attempt to delete the new managed object passed to it. Access to
247  * the object passed to the 'ptr' argument can be obtained via the
248  * thrown Cgu::SharedPtrError object.
249  * @note 1. On systems with over-commit/lazy-commit combined with
250  * virtual memory (swap), it is rarely useful to check for memory
251  * exhaustion, so in those cases this version of the constructor will
252  * not be useful.
253  * @note 2. If the library has been installed using the
254  * \--with-glib-memory-slices-no-compat configuration option this
255  * version of the constructor will also not be useful: instead glib
256  * will terminate the program if it is unable to obtain memory from
257  * the operating system.
258  *
259  * Since 0.9.1
260  */
262 
263  if ((ref_items.obj_p = ptr)) { // not NULL
264 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
265  ref_items.ref_count_p = g_slice_new(unsigned int);
266  *ref_items.ref_count_p = 1;
267 #else
268  try {
269  ref_items.ref_count_p = new unsigned int(1);
270  }
271  catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly
272  throw SharedPtrError<T>(ptr);
273  }
274 #endif
275  }
276  else ref_items.ref_count_p = 0;
277  }
278 
279 /**
280  * Causes the SharedPtr to cease to manage its managed object (if
281  * any), deleting it if this is the last SharedPtr object managing it.
282  * If the argument passed is not NULL, the SharedPtr object will
283  * manage the new object passed (which must not be managed by any
284  * other SharedPtr object). This method is exception safe, but see
285  * the comments below on std::bad_alloc.
286  * @param ptr NULL (the default), or a new unmanaged object to manage.
287  * @exception std::bad_alloc This method will not throw if the 'ptr'
288  * argument has a NULL value (the default) and the destructor of a
289  * managed object does not throw, otherwise it might throw
290  * std::bad_alloc if memory is exhausted and the system throws in that
291  * case. Note that if such an exception is thrown then this method
292  * will do nothing (it is strongly exception safe and will continue to
293  * manage the object it was managing prior to the call), except that
294  * it will delete the new managed object passed to it to avoid a
295  * memory leak. If such automatic deletion in the event of such an
296  * exception is not wanted, use the reset() method taking a
297  * Cgu::SharedPtrAllocFail::Leave tag type as its second argument.
298  * @note std::bad_alloc will not be thrown if the library has been
299  * installed using the \--with-glib-memory-slices-no-compat
300  * configuration option: instead glib will terminate the program if it
301  * is unable to obtain memory from the operating system.
302  *
303  * Since 0.9.1
304  */
305  void reset(T* ptr = 0) {
306  SharedPtr tmp(ptr);
307  std::swap(ref_items, tmp.ref_items);
308  }
309 
310 /**
311  * Causes the SharedPtr to cease to manage its managed object (if
312  * any), deleting it if this is the last SharedPtr object managing it.
313  * The SharedPtr object will manage the new object passed (which must
314  * not be managed by any other SharedPtr object). This method is
315  * exception safe, but see the comments below on Cgu::SharedPtrError.
316  * @param ptr A new unmanaged object to manage (if no new object is to
317  * be managed, use the version of reset() taking a default value of
318  * NULL).
319  * @param tag Passing the tag emumerator
320  * Cgu::SharedPtrAllocFail::leave causes this method not to delete the
321  * new managed object passed as the 'ptr' argument in the event of
322  * internal allocation in this method failing because of memory
323  * exhaustion (in that event, Cgu::SharedPtrError will be thrown).
324  * @exception Cgu::SharedPtrError This method might throw
325  * Cgu::SharedPtrError if memory is exhausted and the system would
326  * otherwise throw std::bad_alloc in that case. Note that if such an
327  * exception is thrown then this method will do nothing (it is
328  * strongly exception safe and will continue to manage the object it
329  * was managing prior to the call), and it will not attempt to delete
330  * the new managed object passed to it. Access to the object passed
331  * to the 'ptr' argument can be obtained via the thrown
332  * Cgu::SharedPtrError object.
333  * @note 1. On systems with over-commit/lazy-commit combined with
334  * virtual memory (swap), it is rarely useful to check for memory
335  * exhaustion, so in those cases this version of the reset() method
336  * will not be useful.
337  * @note 2. If the library has been installed using the
338  * \--with-glib-memory-slices-no-compat configuration option this
339  * version of the reset() method will also not be useful: instead glib
340  * will terminate the program if it is unable to obtain memory from
341  * the operating system.
342  *
343  * Since 0.9.1
344  */
346  SharedPtr tmp(ptr, tag);
347  std::swap(ref_items, tmp.ref_items);
348  }
349 
350  /**
351  * This copy constructor does not throw.
352  * @param sh_ptr The shared pointer to be copied.
353  */
354  SharedPtr(const SharedPtr& sh_ptr) {
355  ref_items = sh_ptr.ref_items;
356  reference();
357  }
358 
359  template <class U> friend class SharedPtr;
360 
361  /**
362  * A version of the copy constructor which enables pointer type
363  * conversion (assuming the type passed is implicitly type
364  * convertible to the managed type, such as a derived type). This
365  * copy constructor does not throw.
366  * @param sh_ptr The shared pointer to be copied.
367  */
368  template <class U> SharedPtr(const SharedPtr<U>& sh_ptr) {
369  // because we are allowing an implicit cast from derived to
370  // base class referenced object, we need to assign from each
371  // member of sh_ptr.ref_items separately
372  ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p;
373  ref_items.obj_p = sh_ptr.ref_items.obj_p;
374  reference();
375  }
376 
377  /**
378  * This method does not throw unless the destructor of a managed
379  * object throws.
380  * @param sh_ptr the assignor.
381  * @return The SharedPtr object after assignment.
382  */
383  // having a value type as the argument, rather than reference to const
384  // and then initialising a tmp object, gives the compiler more scope
385  // for optimisation
387  std::swap(ref_items, sh_ptr.ref_items);
388  return *this;
389  }
390 
391  /**
392  * A version of the assignment operator which enables pointer type
393  * conversion (assuming the type passed is implicitly type
394  * convertible to the managed type, such as a derived type). This
395  * method does not throw unless the destructor of a managed object
396  * throws.
397  * @param sh_ptr the assignor.
398  * @return The SharedPtr object after assignment.
399  */
400  template <class U> SharedPtr& operator=(const SharedPtr<U>& sh_ptr) {
401  return operator=(SharedPtr(sh_ptr));
402  }
403 
404  /**
405  * This method does not throw.
406  * @return A pointer to the managed object (or NULL if none is
407  * managed).
408  */
409  T* get() const {return ref_items.obj_p;}
410 
411  /**
412  * This method does not throw.
413  * @return A reference to the managed object.
414  */
415  T& operator*() const {return *ref_items.obj_p;}
416 
417  /**
418  * This method does not throw.
419  * @return A pointer to the managed object (or NULL if none is
420  * managed).
421  */
422  T* operator->() const {return ref_items.obj_p;}
423 
424  /**
425  * This method does not throw.
426  * @return The number of SharedPtr objects referencing the managed
427  * object (or 0 if none is managed by this SharedPtr).
428  */
429  unsigned int get_refcount() const {return (ref_items.ref_count_p) ? *ref_items.ref_count_p : 0;}
430 
431  /**
432  * The destructor does not throw unless the destructor of a managed
433  * object throws - that should never happen.
434  */
435  ~SharedPtr() {unreference();}
436 };
437 
438 /**
439  * @class SharedLockPtr shared_ptr.h c++-gtk-utils/shared_ptr.h
440  * @brief This is a smart pointer for managing the lifetime of objects
441  * allocated on freestore, with a thread safe reference count.
442  * @ingroup handles
443  * @sa SharedPtr SharedPtrError
444  *
445  * Class SharedLockPtr is a version of the shared pointer class which
446  * includes synchronization so that it can handle objects accessed in
447  * multiple threads (although the word Lock is in the title, by
448  * default it uses glib atomic functions to access the reference count
449  * rather than a mutex, so the overhead should be very small). Note
450  * that only the reference count is protected, so this is thread safe
451  * in the sense in which a raw pointer is thread safe. A shared
452  * pointer accessed in one thread referencing a particular object is
453  * thread safe as against another shared pointer accessing the same
454  * object in a different thread. It is thus suitable for use in
455  * different standard C++ containers which exist in different threads
456  * but which contain shared objects by reference. But:
457  *
458  * 1. If the referenced object is to be modified in one thread and
459  * read or modified in another thread an appropriate mutex for the
460  * referenced object is required (unless that referenced object
461  * does its own locking).
462  * 2. If the same instance of shared pointer is to be modified in one
463  * thread (by assigning to the pointer so that it references a
464  * different object), and copied (assigned from or used as the
465  * argument of a copy constructor), accessed, destroyed or
466  * modified in another thread, a mutex for that instance of shared
467  * pointer is required.
468  * 3. Objects referenced by shared pointers which are objects for
469  * which POSIX provides no guarantees (in the main, those which
470  * are not built-in types), such as strings and similar
471  * containers, may not support concurrent reads in different
472  * threads. That depends on the library implementation concerned.
473  * If that is the case, a mutex for the referenced object will
474  * also be required when reading any given instance of such an
475  * object in more than one thread by dereferencing any shared
476  * pointers referencing it (and indeed, when not using shared
477  * pointers at all).
478  *
479  * As mentioned, by default glib atomic functions are used to provide
480  * thread-safe manipulation of the reference count. However, from
481  * version 1.2.0 the symbol CGU_SHARED_LOCK_PTR_USE_MUTEX can be
482  * defined so that the library uses mutexes instead, which might be
483  * useful for some debugging purposes. Note that if
484  * CGU_SHARED_LOCK_PTR_USE_MUTEX is to be defined, this is best done
485  * by textually amending the shared_ptr.h header file before the
486  * library is compiled. This will ensure that everything in the
487  * program and the library which includes the shared_ptr.h header is
488  * guaranteed to see the same definitions so that the C++ standard's
489  * one-definition-rule is complied with.
490  *
491  * From version 1.2.12, the library provides ==, != and < comparison
492  * operators for SharedLockPtr, but only if the library is compiled
493  * with the \--with-smart-ptr-comp option, or if the user code defines
494  * the symbol CGU_USE_SMART_PTR_COMPARISON before shared_ptr.h is
495  * first parsed. This is because, if user code has provided such
496  * operators for these smart pointers itself, a duplicated function
497  * definition would arise.
498  *
499  * If the library is compiled with the
500  * \--with-glib-memory-slices-no-compat configuration option,
501  * Cgu::SharedLockPtr constructs its reference counting internals
502  * using glib memory slices. Although it is safe in a multi-threaded
503  * program if glib < 2.32 is installed to construct a static
504  * SharedLockPtr object in global namespace (that is, prior to
505  * g_thread_init() being called) by means of the default constructor
506  * and/or a pointer argument of NULL, it is not safe if constructed
507  * with a non-NULL pointer value. If glib >= 2.32 is installed,
508  * global objects with memory slices are safe in all
509  * circumstances. (Having said that, it would be highly unusual to
510  * have global SharedLockPtr objects.)
511  */
512 
513 template <class T> class SharedLockPtr {
514 
515 #ifndef DOXYGEN_PARSING
516  struct RefItems {
517 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
518  Thread::Mutex* mutex_p;
519  unsigned int* ref_count_p;
520 #else
521  gint* ref_count_p;
522 #endif
523  T* obj_p;
524  } ref_items;
525 #endif
526 
527  // SharedLockPtr<T>::unreference() does not throw if the destructor of the
528  // contained object does not throw, because Thread::Mutex::~Mutex(),
529  // Thread::Mutex::lock() and Thread::Mutex::unlock() do not throw
530  void unreference() {
531  // we can (and should) check whether ref_items.ref_count_p is NULL without
532  // a lock, because that member is specific to this SharedLockPtr object.
533  // Only the integer pointed to by it is shared amongst SharedLockPtr
534  // objects and requires locking
535  if (!ref_items.ref_count_p) return;
536 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
537  ref_items.mutex_p->lock();
538  --(*ref_items.ref_count_p);
539  if (*ref_items.ref_count_p == 0) {
540 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
541  g_slice_free(unsigned int, ref_items.ref_count_p);
542 # else
543  delete ref_items.ref_count_p;
544 # endif
545  ref_items.mutex_p->unlock();
546  delete ref_items.mutex_p;
547  delete ref_items.obj_p;
548  }
549  else ref_items.mutex_p->unlock();
550 #else
551  if (g_atomic_int_dec_and_test(ref_items.ref_count_p)) {
552 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
553  g_slice_free(gint, ref_items.ref_count_p);
554 # else
555  delete ref_items.ref_count_p;
556 # endif
557  delete ref_items.obj_p;
558  }
559 #endif
560  }
561 
562  // SharedLockPtr<T>::reference() does not throw because
563  // Thread::Mutex::Lock::Lock() and Thread::Mutex::Lock::~Lock() do not throw
564  void reference() {
565  // we can (and should) check whether ref_items.ref_count_p is NULL without
566  // a lock, because that member is specific to this SharedLockPtr object.
567  // Only the integer pointed to by it is shared amongst SharedLockPtr
568  // objects and requires locking
569  if (!ref_items.ref_count_p) return;
570 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
571  Thread::Mutex::Lock lock(*ref_items.mutex_p);
572  ++(*ref_items.ref_count_p);
573 #else
574  g_atomic_int_inc(ref_items.ref_count_p);
575 #endif
576  }
577 
578 public:
579 /**
580  * Constructor taking an unmanaged object.
581  * @param ptr The object which the SharedLockPtr is to manage (if
582  * any).
583  * @exception std::bad_alloc This constructor will not throw if the
584  * 'ptr' argument has a NULL value (the default), otherwise it might
585  * throw std::bad_alloc if memory is exhausted and the system throws
586  * in that case. If such an exception is thrown, this constructor is
587  * exception safe (it does not leak resources), but as well as
588  * cleaning itself up this constructor will also delete the managed
589  * object passed to it to avoid a memory leak. If such automatic
590  * deletion is not wanted in that case, use the version of this
591  * constructor taking a Cgu::SharedPtrAllocFail::Leave tag argument.
592  * @note 1. std::bad_alloc will not be thrown if the library has been
593  * installed using the \--with-glib-memory-slices-no-compat
594  * configuration option: instead glib will terminate the program if it
595  * is unable to obtain memory from the operating system.
596  * @note 2. By default, glib atomic functions are used to provide
597  * thread-safe manipulation of the reference count. However, from
598  * version 1.2.0 the header file shared_ptr.h can be textually amended
599  * before the library is compiled to define the symbol
600  * CGU_SHARED_LOCK_PTR_USE_MUTEX so as to use mutexes instead, which
601  * might be useful for some debugging purposes. Were that to be done,
602  * Cgu::Thread::MutexError might be thrown by this constructor if
603  * initialization of the mutex fails.
604  */
605  explicit SharedLockPtr(T* ptr = 0) {
606 
607  if ((ref_items.obj_p = ptr)) { // not NULL
608 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
609  try {
610  ref_items.mutex_p = new Thread::Mutex;
611  }
612  catch (...) {
613  delete ptr; // if allocating the object referenced by ref_items.mutex_p
614  // has failed then delete the object to be referenced to
615  // avoid a memory leak
616  throw;
617  }
618 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
619  ref_items.ref_count_p = g_slice_new(unsigned int);
620  *ref_items.ref_count_p = 1;
621 # else
622  try {
623  ref_items.ref_count_p = new unsigned int(1);
624  }
625  catch (...) {
626  delete ref_items.mutex_p;
627  delete ptr;
628  throw;
629  }
630 # endif
631 #else
632 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
633  ref_items.ref_count_p = g_slice_new(gint);
634  *ref_items.ref_count_p = 1;
635 # else
636  try {
637  ref_items.ref_count_p = new gint(1);
638  }
639  catch (...) {
640  delete ptr; // if allocating the int referenced by ref_items.ref_count_p
641  // has failed then delete the object to be referenced to
642  // avoid a memory leak
643  throw;
644  }
645 # endif
646 #endif
647  }
648  else {
649 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
650  ref_items.mutex_p = 0; // make sure the value is valid as we may assign it
651 #endif
652  ref_items.ref_count_p = 0;
653  }
654  }
655 
656 /**
657  * Constructor taking an unmanaged object.
658  * @param ptr The object which the SharedLockPtr is to manage.
659  * @param tag Passing the tag emumerator
660  * Cgu::SharedPtrAllocFail::leave causes this constructor not to
661  * delete the new managed object passed as the 'ptr' argument in the
662  * event of internal allocation in this method failing because of
663  * memory exhaustion (in that event, Cgu::SharedPtrError will be
664  * thrown).
665  * @exception Cgu::SharedPtrError This constructor might throw
666  * Cgu::SharedPtrError if memory is exhausted and the system would
667  * otherwise throw std::bad_alloc in that case. This constructor is
668  * exception safe (it does not leak resources), and if such an
669  * exception is thrown it will clean itself up, but it will not
670  * attempt to delete the new managed object passed to it. Access to
671  * the object passed to the 'ptr' argument can be obtained via the
672  * thrown Cgu::SharedPtrError object.
673  * @note 1. On systems with over-commit/lazy-commit combined with
674  * virtual memory (swap), it is rarely useful to check for memory
675  * exhaustion, so in those cases this version of the constructor will
676  * not be useful.
677  * @note 2. If the library has been installed using the
678  * \--with-glib-memory-slices-no-compat configuration option this
679  * version of the constructor will also not be useful: instead glib
680  * will terminate the program if it is unable to obtain memory from
681  * the operating system.
682  * @note 3. By default, glib atomic functions are used to provide
683  * thread-safe manipulation of the reference count. However, from
684  * version 1.2.0 the header file shared_ptr.h can be textually amended
685  * before the library is compiled to define the symbol
686  * CGU_SHARED_LOCK_PTR_USE_MUTEX so as to use mutexes instead, which
687  * might be useful for some debugging purposes. Were that to be done,
688  * Cgu::SharedPtrError might be thrown by this constructor if
689  * initialization of the mutex fails (even if the
690  * \--with-glib-memory-slices-no-compat configuration option is
691  * chosen).
692  *
693  * Since 0.9.1
694  */
696 
697  if ((ref_items.obj_p = ptr)) { // not NULL
698 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
699  try {
700  ref_items.mutex_p = new Thread::Mutex;
701  }
702  catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly
703  throw SharedPtrError<T>(ptr);
704  }
705  catch (Thread::MutexError&) { // as we are not rethrowing, make NPTL friendly
706  throw SharedPtrError<T>(ptr);
707  }
708 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
709  ref_items.ref_count_p = g_slice_new(unsigned int);
710  *ref_items.ref_count_p = 1;
711 # else
712  try {
713  ref_items.ref_count_p = new unsigned int(1);
714  }
715  catch (std::bad_alloc&) {
716  delete ref_items.mutex_p;
717  throw SharedPtrError<T>(ptr);
718  }
719 # endif
720 #else
721 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT
722  ref_items.ref_count_p = g_slice_new(gint);
723  *ref_items.ref_count_p = 1;
724 # else
725  try {
726  ref_items.ref_count_p = new gint(1);
727  }
728  catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly
729  throw SharedPtrError<T>(ptr);
730  }
731 # endif
732 #endif
733  }
734  else {
735 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
736  ref_items.mutex_p = 0; // make sure the value is valid as we may assign it
737 #endif
738  ref_items.ref_count_p = 0;
739  }
740  }
741 
742 /**
743  * Causes the SharedLockPtr to cease to manage its managed object (if
744  * any), deleting it if this is the last SharedLockPtr object managing
745  * it. If the argument passed is not NULL, the SharedLockPtr object
746  * will manage the new object passed (which must not be managed by any
747  * other SharedLockPtr object). This method is exception safe, but
748  * see the comments below on std::bad_alloc.
749  * @param ptr NULL (the default), or a new unmanaged object to manage.
750  * @exception std::bad_alloc This method will not throw if the 'ptr'
751  * argument has a NULL value (the default) and the destructor of a
752  * managed object does not throw, otherwise it might throw
753  * std::bad_alloc if memory is exhausted and the system throws in that
754  * case. Note that if such an exception is thrown then this method
755  * will do nothing (it is strongly exception safe and will continue to
756  * manage the object it was managing prior to the call), except that
757  * it will delete the new managed object passed to it to avoid a
758  * memory leak. If such automatic deletion in the event of such an
759  * exception is not wanted, use the reset() method taking a
760  * Cgu::SharedPtrAllocFail::Leave tag type as its second argument.
761  * @note 1. std::bad_alloc will not be thrown if the library has been
762  * installed using the \--with-glib-memory-slices-no-compat
763  * configuration option: instead glib will terminate the program if it
764  * is unable to obtain memory from the operating system.
765  * @note 2. By default, glib atomic functions are used to provide
766  * thread-safe manipulation of the reference count. However, from
767  * version 1.2.0 the header file shared_ptr.h can be textually amended
768  * before the library is compiled to define the symbol
769  * CGU_SHARED_LOCK_PTR_USE_MUTEX so as to use mutexes instead, which
770  * might be useful for some debugging purposes. Were that to be done,
771  * Cgu::Thread::MutexError might be thrown by this method if
772  * initialization of the mutex fails.
773  * @note 3. A SharedLockPtr object protects its reference count but
774  * not the managed object or its other internals. The reset() method
775  * should not be called by one thread in respect of a particular
776  * SharedLockPtr object while another thread may be operating on,
777  * copying or dereferencing the same instance of SharedLockPtr. It is
778  * thread-safe as against another instance of SharedLockPtr managing
779  * the same object.
780  *
781  * Since 0.9.1
782  */
783  void reset(T* ptr = 0) {
784  SharedLockPtr tmp(ptr);
785  std::swap(ref_items, tmp.ref_items);
786  }
787 
788 /**
789  * Causes the SharedLockPtr to cease to manage its managed object (if
790  * any), deleting it if this is the last SharedLockPtr object managing
791  * it. The SharedLockPtr object will manage the new object passed
792  * (which must not be managed by any other SharedLockPtr object).
793  * This method is exception safe, but see the comments below on
794  * Cgu::SharedPtrError.
795  * @param ptr A new unmanaged object to manage (if no new object is to
796  * be managed, use the version of reset() taking a default value of
797  * NULL).
798  * @param tag Passing the tag emumerator
799  * Cgu::SharedPtrAllocFail::leave causes this method not to delete the
800  * new managed object passed as the 'ptr' argument in the event of
801  * internal allocation in this method failing because of memory
802  * exhaustion (in that event, Cgu::SharedPtrError will be thrown).
803  * @exception Cgu::SharedPtrError This method might throw
804  * Cgu::SharedPtrError if memory is exhausted and the system would
805  * otherwise throw std::bad_alloc in that case. Note that if such an
806  * exception is thrown then this method will do nothing (it is
807  * strongly exception safe and will continue to manage the object it
808  * was managing prior to the call), and it will not attempt to delete
809  * the new managed object passed to it. Access to the object passed
810  * to the 'ptr' argument can be obtained via the thrown
811  * Cgu::SharedPtrError object.
812  * @note 1. A SharedLockPtr object protects its reference count but
813  * not the managed object or its other internals. The reset() method
814  * should not be called by one thread in respect of a particular
815  * SharedLockPtr object while another thread may be operating on,
816  * copying or dereferencing the same instance of SharedLockPtr. It is
817  * thread-safe as against another instance of SharedLockPtr managing
818  * the same object.
819  * @note 2. On systems with over-commit/lazy-commit combined with
820  * virtual memory (swap), it is rarely useful to check for memory
821  * exhaustion, so in those cases this version of the reset() method
822  * will not be useful.
823  * @note 3. If the library has been installed using the
824  * \--with-glib-memory-slices-no-compat configuration option this
825  * version of the reset() method will also not be useful: instead glib
826  * will terminate the program if it is unable to obtain memory from
827  * the operating system.
828  * @note 4. By default, glib atomic functions are used to provide
829  * thread-safe manipulation of the reference count. However, from
830  * version 1.2.0 the header file shared_ptr.h can be textually amended
831  * before the library is compiled to define the symbol
832  * CGU_SHARED_LOCK_PTR_USE_MUTEX so as to use mutexes instead, which
833  * might be useful for some debugging purposes. Were that to be done,
834  * Cgu::SharedPtrError might be thrown by this method if
835  * initialization of the mutex fails (even if the
836  * \--with-glib-memory-slices-no-compat configuration option is
837  * chosen).
838  *
839  * Since 0.9.1
840  */
842  SharedLockPtr tmp(ptr, tag);
843  std::swap(ref_items, tmp.ref_items);
844  }
845 
846  /**
847  * This copy constructor does not throw.
848  * @param sh_ptr The shared pointer to be copied.
849  */
850  SharedLockPtr(const SharedLockPtr& sh_ptr) {
851  ref_items = sh_ptr.ref_items;
852  reference();
853  }
854 
855  template <class U> friend class SharedLockPtr;
856 
857  /**
858  * A version of the copy constructor which enables pointer type
859  * conversion (assuming the type passed is implicitly type
860  * convertible to the managed type, such as a derived type). This
861  * copy constructor does not throw.
862  * @param sh_ptr The shared pointer to be copied.
863  */
864  template <class U> SharedLockPtr(const SharedLockPtr<U>& sh_ptr) {
865  // because we are allowing an implicit cast from derived to
866  // base class referenced object, we need to assign from each
867  // member of sh_ptr.ref_items separately
868 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
869  ref_items.mutex_p = sh_ptr.ref_items.mutex_p;
870 #endif
871  ref_items.obj_p = sh_ptr.ref_items.obj_p;
872  ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p;
873  reference();
874  }
875 
876  /**
877  * This method does not throw unless the destructor of a managed
878  * object throws.
879  * @param sh_ptr the assignor.
880  * @return The SharedLockPtr object after assignment.
881  */
882  // having a value type as the argument rather than reference to const
883  // and then initialising a tmp object gives the compiler more scope
884  // for optimisation
886  std::swap(ref_items, sh_ptr.ref_items);
887  return *this;
888  }
889 
890  /**
891  * A version of the assignment operator which enables pointer type
892  * conversion (assuming the type passed is implicitly type
893  * convertible to the managed type, such as a derived type). This
894  * method does not throw unless the destructor of a managed object
895  * throws.
896  * @param sh_ptr the assignor.
897  * @return The SharedLockPtr object after assignment.
898  */
899  template <class U> SharedLockPtr& operator=(const SharedLockPtr<U>& sh_ptr) {
900  return operator=(SharedLockPtr(sh_ptr));
901  }
902 
903  /**
904  * This method does not throw.
905  * @return A pointer to the managed object (or NULL if none is
906  * managed).
907  */
908  T* get() const {return ref_items.obj_p;}
909 
910  /**
911  * This method does not throw.
912  * @return A reference to the managed object.
913  */
914  T& operator*() const {return *ref_items.obj_p;}
915 
916  /**
917  * This method does not throw.
918  * @return A pointer to the managed object (or NULL if none is
919  * managed).
920  */
921  T* operator->() const {return ref_items.obj_p;}
922 
923  /**
924  * This method does not throw.
925  * @return The number of SharedLockPtr objects referencing the
926  * managed object (or 0 if none is managed by this SharedLockPtr).
927  * @note The return value may not be valid if another thread has
928  * changed the reference count before the value returned by this
929  * method is acted on. It is provided as a utility, but may not be
930  * meaningful, depending on the intended usage.
931  */
932  unsigned int get_refcount() const {
933  if (!ref_items.ref_count_p) return 0;
934 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX
935  Thread::Mutex::Lock lock(*ref_items.mutex_p);
936  return *ref_items.ref_count_p;
937 #else
938  return g_atomic_int_get(ref_items.ref_count_p);
939 #endif
940  }
941 
942  /**
943  * The destructor does not throw unless the destructor of a managed
944  * object throws - that should never happen.
945  */
946  ~SharedLockPtr() {unreference();}
947 };
948 
949 #if defined(CGU_USE_SMART_PTR_COMPARISON) || defined(DOXYGEN_PARSING)
950 
951 // we can use built-in operator == when comparing pointers referencing
952 // different objects of the same type
953 /**
954  * @ingroup handles
955  *
956  * This comparison operator does not throw. It compares the addresses
957  * of the managed objects. This function is only available if the
958  * library is compiled with the \--with-smart-ptr-comp option, or if
959  * the user code defines the symbol CGU_USE_SMART_PTR_COMPARISON
960  * before shared_ptr.h is first parsed.
961  *
962  * Since 1.2.12
963  */
964 template <class T>
965 bool operator==(const SharedPtr<T>& s1, const SharedPtr<T>& s2) {
966  return (s1.get() == s2.get());
967 }
968 
969 /**
970  * @ingroup handles
971  *
972  * This comparison operator does not throw. It compares the addresses
973  * of the managed objects. This function is only available if the
974  * library is compiled with the \--with-smart-ptr-comp option, or if
975  * the user code defines the symbol CGU_USE_SMART_PTR_COMPARISON
976  * before shared_ptr.h is first parsed.
977  *
978  * Since 1.2.12
979  */
980 template <class T>
981 bool operator!=(const SharedPtr<T>& s1, const SharedPtr<T>& s2) {
982  return !(s1 == s2);
983 }
984 
985 // we must use std::less rather than the < built-in operator for
986 // pointers to objects not within the same array or object: "For
987 // templates greater, less, greater_equal, and less_equal, the
988 // specializations for any pointer type yield a total order, even if
989 // the built-in operators <, >, <=, >= do not." (para 20.3.3/8).
990 /**
991  * @ingroup handles
992  *
993  * This comparison operator does not throw unless std::less applied to
994  * pointer types throws (which it would not do with any sane
995  * implementation). It compares the addresses of the managed objects.
996  * This function is only available if the library is compiled with the
997  * \--with-smart-ptr-comp option, or if the user code defines the
998  * symbol CGU_USE_SMART_PTR_COMPARISON before shared_ptr.h is first
999  * parsed.
1000  *
1001  * Since 1.2.12
1002  */
1003 template <class T>
1004 bool operator<(const SharedPtr<T>& s1, const SharedPtr<T>& s2) {
1005  return std::less<T*>()(s1.get(), s2.get());
1006 }
1007 
1008 /**
1009  * @ingroup handles
1010  *
1011  * This comparison operator does not throw. It compares the addresses
1012  * of the managed objects. This function is only available if the
1013  * library is compiled with the \--with-smart-ptr-comp option, or if
1014  * the user code defines the symbol CGU_USE_SMART_PTR_COMPARISON
1015  * before shared_ptr.h is first parsed.
1016  *
1017  * Since 1.2.12
1018  */
1019 template <class T>
1020 bool operator==(const SharedLockPtr<T>& s1, const SharedLockPtr<T>& s2) {
1021  return (s1.get() == s2.get());
1022 }
1023 
1024 /**
1025  * @ingroup handles
1026  *
1027  * This comparison operator does not throw. It compares the addresses
1028  * of the managed objects. This function is only available if the
1029  * library is compiled with the \--with-smart-ptr-comp option, or if
1030  * the user code defines the symbol CGU_USE_SMART_PTR_COMPARISON
1031  * before shared_ptr.h is first parsed.
1032  *
1033  * Since 1.2.12
1034  */
1035 template <class T>
1036 bool operator!=(const SharedLockPtr<T>& s1, const SharedLockPtr<T>& s2) {
1037  return !(s1 == s2);
1038 }
1039 
1040 /**
1041  * @ingroup handles
1042  *
1043  * This comparison operator does not throw unless std::less applied to
1044  * pointer types throws (which it would not do with any sane
1045  * implementation). It compares the addresses of the managed objects.
1046  * This function is only available if the library is compiled with the
1047  * \--with-smart-ptr-comp option, or if the user code defines the
1048  * symbol CGU_USE_SMART_PTR_COMPARISON before shared_ptr.h is first
1049  * parsed.
1050  *
1051  * Since 1.2.12
1052  */
1053 template <class T>
1054 bool operator<(const SharedLockPtr<T>& s1, const SharedLockPtr<T>& s2) {
1055  return std::less<T*>()(s1.get(), s2.get());
1056 }
1057 
1058 #endif // CGU_USE_SMART_PTR_COMPARISON
1059 
1060 } // namespace Cgu
1061 
1062 #endif
Cgu::SharedPtrError
This is an exception struct thrown as an alternative to deleting a managed object when internal memor...
Definition: shared_ptr.h:113
Cgu::SharedLockPtr::operator=
SharedLockPtr & operator=(SharedLockPtr sh_ptr)
Definition: shared_ptr.h:885
Cgu::SharedPtr::operator=
SharedPtr & operator=(const SharedPtr< U > &sh_ptr)
Definition: shared_ptr.h:400
Cgu
Definition: application.h:45
Cgu::SharedLockPtr::SharedLockPtr
SharedLockPtr(T *ptr, Cgu::SharedPtrAllocFail::Leave tag)
Definition: shared_ptr.h:695
Cgu::SharedLockPtr::SharedLockPtr
SharedLockPtr(const SharedLockPtr &sh_ptr)
Definition: shared_ptr.h:850
Cgu::SharedLockPtr::get
T * get() const
Definition: shared_ptr.h:908
Cgu::SharedLockPtr::reset
void reset(T *ptr, Cgu::SharedPtrAllocFail::Leave tag)
Definition: shared_ptr.h:841
Cgu::SharedLockPtr::operator->
T * operator->() const
Definition: shared_ptr.h:921
Cgu::SharedPtr::reset
void reset(T *ptr, Cgu::SharedPtrAllocFail::Leave tag)
Definition: shared_ptr.h:345
Cgu::SharedPtrAllocFail::leave
@ leave
Definition: shared_ptr.h:129
Cgu::SharedLockPtr::reset
void reset(T *ptr=0)
Definition: shared_ptr.h:783
Cgu::operator!=
bool operator!=(const GobjHandle< T > &h1, const GobjHandle< T > &h2)
Definition: gobj_handle.h:618
Cgu::SharedPtr::get_refcount
unsigned int get_refcount() const
Definition: shared_ptr.h:429
Cgu::SharedPtr::SharedPtr
SharedPtr(const SharedPtr &sh_ptr)
Definition: shared_ptr.h:354
Cgu::SharedPtrError::obj
T * obj
Definition: shared_ptr.h:114
Cgu::SharedLockPtr::operator=
SharedLockPtr & operator=(const SharedLockPtr< U > &sh_ptr)
Definition: shared_ptr.h:899
Cgu::operator<
bool operator<(const GobjHandle< T > &h1, const GobjHandle< T > &h2)
Definition: gobj_handle.h:641
Cgu::swap
void swap(Cgu::AsyncQueue< T, Container > &q1, Cgu::AsyncQueue< T, Container > &q2)
Definition: async_queue.h:784
Cgu::SharedLockPtr::~SharedLockPtr
~SharedLockPtr()
Definition: shared_ptr.h:946
Cgu::SharedPtr::operator=
SharedPtr & operator=(SharedPtr sh_ptr)
Definition: shared_ptr.h:386
Cgu::SharedPtr
This is a smart pointer for managing the lifetime of objects allocated on freestore.
Definition: shared_ptr.h:166
Cgu::SharedPtrAllocFail::Leave
Leave
Definition: shared_ptr.h:129
Cgu::SharedPtr::get
T * get() const
Definition: shared_ptr.h:409
Cgu::SharedPtr::reset
void reset(T *ptr=0)
Definition: shared_ptr.h:305
Cgu::SharedPtr::SharedPtr
SharedPtr(T *ptr=0)
Definition: shared_ptr.h:211
Cgu::SharedPtr::~SharedPtr
~SharedPtr()
Definition: shared_ptr.h:435
Cgu::SharedPtrError::what
virtual const char * what() const
Definition: shared_ptr.h:115
Cgu::Thread::Mutex::lock
int lock()
Definition: mutex.h:132
Cgu::Thread::Mutex::Lock
A scoped locking class for exception safe Mutex locking.
Definition: mutex.h:192
Cgu::SharedLockPtr::SharedLockPtr
friend class SharedLockPtr
Definition: shared_ptr.h:855
Cgu::SharedLockPtr::SharedLockPtr
SharedLockPtr(T *ptr=0)
Definition: shared_ptr.h:605
Cgu::SharedPtr::operator*
T & operator*() const
Definition: shared_ptr.h:415
Cgu::SharedPtr::SharedPtr
SharedPtr(T *ptr, Cgu::SharedPtrAllocFail::Leave tag)
Definition: shared_ptr.h:261
mutex.h
Provides wrapper classes for pthread mutexes and condition variables, and scoped locking classes for ...
Cgu::SharedLockPtr
This is a smart pointer for managing the lifetime of objects allocated on freestore,...
Definition: shared_ptr.h:513
Cgu::SharedPtr::SharedPtr
SharedPtr(const SharedPtr< U > &sh_ptr)
Definition: shared_ptr.h:368
Cgu::operator==
bool operator==(const GobjHandle< T > &h1, const GobjHandle< T > &h2)
Definition: gobj_handle.h:602
Cgu::SharedLockPtr::operator*
T & operator*() const
Definition: shared_ptr.h:914
Cgu::SharedPtr::SharedPtr
friend class SharedPtr
Definition: shared_ptr.h:359
Cgu::SharedPtr::operator->
T * operator->() const
Definition: shared_ptr.h:422
Cgu::Thread::MutexError
Definition: mutex.h:81
Cgu::Thread::Mutex
A wrapper class for pthread mutexes.
Definition: mutex.h:109
cgu_config.h
Cgu::SharedLockPtr::SharedLockPtr
SharedLockPtr(const SharedLockPtr< U > &sh_ptr)
Definition: shared_ptr.h:864
Cgu::SharedLockPtr::get_refcount
unsigned int get_refcount() const
Definition: shared_ptr.h:932
Cgu::SharedPtrError::SharedPtrError
SharedPtrError(T *p)
Definition: shared_ptr.h:116