c++-gtk-utils
intrusive_ptr.h
Go to the documentation of this file.
1 /* Copyright (C) 2006 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_INTRUSIVE_PTR_H
40 #define CGU_INTRUSIVE_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 // IntrusiveLockCounter class
45 /* #define CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX 1 */
46 
47 #include <functional> // for std::less
48 #include <algorithm> // for std::swap (c++98)
49 #include <utility> // for std::swap (c++11)
50 
51 #ifdef CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX
52 #include <c++-gtk-utils/mutex.h>
53 #else
54 #include <glib.h>
55 #endif
56 
58 
59 /**
60  * @addtogroup handles handles and smart pointers
61  */
62 
63 namespace Cgu {
64 
65 /**
66  * @class IntrusivePtr intrusive_ptr.h c++-gtk-utils/intrusive_ptr.h
67  * @brief This is a smart pointer for managing objects allocated on
68  * freestore which maintain their own reference count.
69  * @ingroup handles
70  *
71  * @details This is a class which manages objects which maintain their
72  * own reference count. It requires that the referenced object has
73  * two functions called ref() and unref(), which increment and
74  * decrement the reference count respectively. The IntrusiveCounter
75  * or IntrusiveLockCounter class can be inherited from to do this, but
76  * they do not have to be used. The IntrusiveLockCounter class is the
77  * same as the IntrusiveCounter class, except that it locks the
78  * reference count when it is incremented or decremented in order that
79  * IntrusivePtr objects in different threads can access the same
80  * object. (But only the reference count is locked, not the methods
81  * of the referenced object.)
82  *
83  * All the constructors (including the constructor which takes a raw
84  * pointer) increment the reference count, and the destructor
85  * decrements it and expects the referenced object to be deleted when
86  * the last IntrusivePtr referencing a particular object is destroyed.
87  * The IntrusiveCounter and IntrusiveLockCounter classes behave in
88  * this way. (This is different from the behaviour of GobjHandle
89  * smart pointers, which are constrained by the GObject reference
90  * counting system which begins with a reference count of 1 rather
91  * than 0, and of course different from normal shared pointer
92  * implementations for the same reason. The advantage of the approach
93  * with IntrusivePtr is that an already-managed object may safely be
94  * passed to the constructor taking a raw pointer without any
95  * additional steps being necessary.)
96  *
97  * From version 1.2.12, the library provides ==, != and < comparison
98  * operators for IntrusivePtr, but only if the library is compiled
99  * with the \--with-smart-ptr-comp option, or if the user code defines
100  * the symbol CGU_USE_SMART_PTR_COMPARISON before intrusive_ptr.h is
101  * first parsed. This is because, if user code has provided such
102  * operators for these smart pointers itself, a duplicated function
103  * definition would arise.
104  */
105 
106 template <class T> class IntrusivePtr {
107 
108  T* obj_p;
109 
110  void unreference() {
111  if (obj_p) obj_p->unref();
112  }
113 
114  void reference() {
115  if (obj_p) obj_p->ref();
116  }
117 
118 public:
119  /**
120  * This constructor does not throw unless the managed object's ref()
121  * function throws (which would not happen with any sane
122  * implementation, and does not happen with the IntrusiveCounter and
123  * IntrusiveLockCounter classes).
124  * @param ptr The object which the IntrusivePtr is to manage (if
125  * any).
126  */
127  explicit IntrusivePtr(T* ptr = 0) {
128  obj_p = ptr;
129  reference();
130  }
131 
132  /**
133  * This copy constructor does not throw unless the managed object's
134  * ref() function throws (which would not happen with any sane
135  * implementation, and does not happen with the IntrusiveCounter and
136  * IntrusiveLockCounter classes).
137  * @param intr_ptr The intrusive pointer to be copied.
138  */
139  IntrusivePtr(const IntrusivePtr& intr_ptr) {
140  obj_p = intr_ptr.obj_p;
141  reference();
142  }
143 
144  template <class U> friend class IntrusivePtr;
145 
146  /**
147  * A version of the copy constructor which enables pointer type
148  * conversion (assuming the type passed is implicitly type
149  * convertible to the managed type, such as a derived type). This
150  * copy constructor does not throw unless the managed object's ref()
151  * function throws (which would not happen with any sane
152  * implementation, and does not happen with the IntrusiveCounter and
153  * IntrusiveLockCounter classes).
154  * @param intr_ptr The intrusive pointer to be copied.
155  */
156  template <class U> IntrusivePtr(const IntrusivePtr<U>& intr_ptr) {
157  obj_p = intr_ptr.obj_p;
158  reference();
159  }
160 
161  /**
162  * This method does not throw unless the unref() function or
163  * destructor of a managed object throws.
164  * @param intr_ptr The assignee.
165  * @return The IntrusivePtr object after assignment.
166  */
167  // having a value type as the argument, rather than reference to const
168  // and then initialising a tmp object, gives the compiler more scope
169  // for optimisation
171  std::swap(obj_p, intr_ptr.obj_p);
172  return *this;
173  }
174 
175  /**
176  * A version of the assignment operator which enables pointer type
177  * conversion (assuming the type passed is implicitly type
178  * convertible to the managed type, such as a derived type). This
179  * method does not throw unless the unref() function or destructor of
180  * a managed object throws.
181  * @param intr_ptr The assignee.
182  * @return The IntrusivePtr object after assignment.
183  */
184  template <class U> IntrusivePtr& operator=(const IntrusivePtr<U>& intr_ptr) {
185  return operator=(IntrusivePtr(intr_ptr));
186  }
187 
188  /**
189  * This method does not throw.
190  * @return A pointer to the managed object (or NULL if none is
191  * managed).
192  */
193  T* get() const {return obj_p;}
194 
195  /**
196  * This method does not throw.
197  * @return A reference to the managed object.
198  */
199  T& operator*() const {return *obj_p;}
200 
201  /**
202  * This method does not throw.
203  * @return A pointer to the managed object (or NULL if none is
204  * managed).
205  */
206  T* operator->() const {return obj_p;}
207 
208  /**
209  * Causes the intrusive pointer to cease to manage its managed
210  * object, deleting it if this is the last intrusive pointer managing
211  * it. If the argument passed is not NULL, the intrusive pointer
212  * will manage the new object passed. This method does not throw
213  * unless the unref() function or destructor of a managed object
214  * throws.
215  * @param ptr NULL (the default), or a new object to manage.
216  *
217  * Since 0.9.1
218  */
219  void reset(T* ptr = 0) {
220  IntrusivePtr tmp(ptr);
221  std::swap(obj_p, tmp.obj_p);
222  }
223 
224  /**
225  * The destructor does not throw unless the destructor of a managed
226  * object throws - that should never happen.
227  */
228  ~IntrusivePtr() {unreference();}
229 };
230 
231 /**
232  * @class IntrusiveCounter intrusive_ptr.h c++-gtk-utils/intrusive_ptr.h
233  * @brief This is a counter class providing the ref() and unref()
234  * functions required by IntrusivePtr.
235  * @ingroup handles
236  * @sa IntrusiveLockCounter.
237  *
238  * This is a counter class providing the ref() and unref() functions
239  * required by IntrusivePtr. It is intended to be inherited from by
240  * classes which are to be managed by such a smart pointer.
241  */
242 
244  unsigned int count;
245 
246  // we should not be able to copy objects of this class
247  // - objects, if constructed on the heap, should be passed
248  // via an IntrusivePtr object. An object of a derived class
249  // might still copy itself via its copy constructor and take
250  // along a new base IntrusiveCounter object constructed via
251  // the default constructor, and thus have a correct reference
252  // count of 0, but derived classes should not try to provide
253  // their own assignment operators.
255  IntrusiveCounter& operator=(const IntrusiveCounter&);
256 public:
257 /**
258  * Increments the reference count. This method does not throw.
259  */
260  void ref() {++count;}
261 
262 /**
263  * Decrements the reference count, and if the count reaches 0 deletes
264  * itself (ie the managed object). This method does not throw unless
265  * the destructor of a derived class throws - that should never
266  * happen.
267  */
268  void unref() {
269  --count;
270  if (count == 0) delete this;
271  }
272 
273 /**
274  * The constructor does not throw.
275  */
276  IntrusiveCounter(): count(0) {}
277 
278 /**
279  * This destructor does not throw, unless the destructor of a derived
280  * class throws - that should never happen.
281  */
282  virtual ~IntrusiveCounter() {}
283 };
284 
285 /**
286  * @class IntrusiveLockCounter intrusive_ptr.h c++-gtk-utils/intrusive_ptr.h
287  * @brief This is a counter class providing the ref() and unref()
288  * functions required by IntrusivePtr, with a thread safe reference
289  * count..
290  * @ingroup handles
291  * @sa IntrusiveCounter.
292  *
293  * This is a counter class providing the ref() and unref() functions
294  * required by IntrusivePtr. It is intended to be inherited from by
295  * classes which are to be managed by such a smart pointer, and
296  * includes synchronization so that such an inheriting class object
297  * can be accessed by different IntrusivePtr objects in different
298  * threads (although the word Lock is in the title, by default it uses
299  * glib atomic functions to access the reference count rather than a
300  * mutex, so the overhead should be very small). Note that only the
301  * reference count is protected, so this is thread safe in the sense
302  * in which a raw pointer is thread safe.
303  *
304  * As mentioned, by default glib atomic functions are used to provide
305  * thread-safe manipulation of the reference count. However, from
306  * version 1.2.0 the symbol CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX can
307  * be defined so that the library uses mutexes instead, which might be
308  * useful for some debugging purposes. Note that if
309  * CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX is to be defined, this is best
310  * done by textually amending the intrusive_ptr.h header file before
311  * the library is compiled. This will ensure that everything in the
312  * program and the library which includes the intrusive_ptr.h header
313  * is guaranteed to see the same definitions so that the C++
314  * standard's one-definition-rule is complied with.
315  */
316 
318 #ifdef CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX
319  unsigned int count;
320  Thread::Mutex mutex;
321 #else
322  gint count;
323 #endif
324 
325  // we should not be able to copy objects of this class
326  // - objects, if constructed on the heap, should be passed
327  // via an IntrusivePtr object. An object of a derived class
328  // might still copy itself via its copy constructor and take
329  // along a new base IntrusiveLockCounter object constructed via
330  // the default constructor, and thus have a correct reference
331  // count of 0, but derived classes should not try to provide
332  // their own assignment operators.
334  IntrusiveLockCounter& operator=(const IntrusiveLockCounter&);
335 public:
336 /**
337  * Increments the reference count. This method does not throw.
338  */
339  void ref() {
340 #ifdef CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX
341  Thread::Mutex::Lock lock(mutex);
342  ++count;
343 #else
344  g_atomic_int_inc(&count);
345 #endif
346  }
347 
348 /**
349  * Decrements the reference count, and if the count reaches 0 deletes
350  * itself (ie the managed object). This method does not throw unless
351  * the destructor of a derived class throws - that should never
352  * happen.
353  */
354  void unref() {
355 #ifdef CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX
356  mutex.lock();
357  --count;
358  if (count == 0) {
359  mutex.unlock();
360  delete this;
361  }
362  else mutex.unlock();
363 #else
364  if (g_atomic_int_dec_and_test(&count)) {
365  delete this;
366  }
367 #endif
368  }
369 
370 /**
371  * By default, glib atomic functions are used to provide thread-safe
372  * manipulation of the reference count. However, from version 1.2.0
373  * the header file intrusive_ptr.h can be textually amended before the
374  * library is compiled to define the symbol
375  * CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX so as to use mutexes instead,
376  * which might be useful for some debugging purposes. Were that to be
377  * done, Cgu::Thread::MutexError might be thrown by this constructor
378  * if initialization of the mutex fails.
379  *
380  * Otherwise, this constructor does not throw.
381  */
382  IntrusiveLockCounter(): count(0) {}
383 
384 /**
385  * This destructor does not throw, unless the destructor of a derived
386  * class throws - that should never happen.
387  */
389 };
390 
391 #if defined(CGU_USE_SMART_PTR_COMPARISON) || defined(DOXYGEN_PARSING)
392 
393 // we can use built-in operator == when comparing pointers referencing
394 // different objects of the same type
395 /**
396  * @ingroup handles
397  *
398  * This comparison operator does not throw. It compares the addresses
399  * of the managed objects. This function is only available if the
400  * library is compiled with the \--with-smart-ptr-comp option, or if
401  * the user code defines the symbol CGU_USE_SMART_PTR_COMPARISON
402  * before intrusive_ptr.h is first parsed.
403  *
404  * Since 1.2.12
405  */
406 template <class T>
407 bool operator==(const IntrusivePtr<T>& s1, const IntrusivePtr<T>& s2) {
408  return (s1.get() == s2.get());
409 }
410 
411 /**
412  * @ingroup handles
413  *
414  * This comparison operator does not throw. It compares the addresses
415  * of the managed objects. This function is only available if the
416  * library is compiled with the \--with-smart-ptr-comp option, or if
417  * the user code defines the symbol CGU_USE_SMART_PTR_COMPARISON
418  * before intrusive_ptr.h is first parsed.
419  *
420  * Since 1.2.12
421  */
422 template <class T>
423 bool operator!=(const IntrusivePtr<T>& s1, const IntrusivePtr<T>& s2) {
424  return !(s1 == s2);
425 }
426 
427 // we must use std::less rather than the < built-in operator for
428 // pointers to objects not within the same array or object: "For
429 // templates greater, less, greater_equal, and less_equal, the
430 // specializations for any pointer type yield a total order, even if
431 // the built-in operators <, >, <=, >= do not." (para 20.3.3/8).
432 /**
433  * @ingroup handles
434  *
435  * This comparison operator does not throw unless std::less applied to
436  * pointer types throws (which it would not do with any sane
437  * implementation). It compares the addresses of the managed objects.
438  * This function is only available if the library is compiled with the
439  * \--with-smart-ptr-comp option, or if the user code defines the
440  * symbol CGU_USE_SMART_PTR_COMPARISON before intrusive_ptr.h is first
441  * parsed.
442  *
443  * Since 1.2.12
444  */
445 template <class T>
446 bool operator<(const IntrusivePtr<T>& s1, const IntrusivePtr<T>& s2) {
447  return std::less<T*>()(s1.get(), s2.get());
448 }
449 
450 #endif // CGU_USE_SMART_PTR_COMPARISON
451 
452 } // namespace Cgu
453 
454 #endif
Cgu::IntrusivePtr::operator*
T & operator*() const
Definition: intrusive_ptr.h:199
Cgu
Definition: application.h:45
Cgu::IntrusiveLockCounter::~IntrusiveLockCounter
virtual ~IntrusiveLockCounter()
Definition: intrusive_ptr.h:388
Cgu::IntrusiveCounter
This is a counter class providing the ref() and unref() functions required by IntrusivePtr.
Definition: intrusive_ptr.h:243
Cgu::operator!=
bool operator!=(const GobjHandle< T > &h1, const GobjHandle< T > &h2)
Definition: gobj_handle.h:618
Cgu::IntrusivePtr
This is a smart pointer for managing objects allocated on freestore which maintain their own referenc...
Definition: intrusive_ptr.h:106
Cgu::IntrusiveCounter::ref
void ref()
Definition: intrusive_ptr.h:260
Cgu::IntrusiveLockCounter::unref
void unref()
Definition: intrusive_ptr.h:354
Cgu::IntrusivePtr::operator->
T * operator->() const
Definition: intrusive_ptr.h:206
Cgu::operator<
bool operator<(const GobjHandle< T > &h1, const GobjHandle< T > &h2)
Definition: gobj_handle.h:641
Cgu::IntrusiveLockCounter::ref
void ref()
Definition: intrusive_ptr.h:339
Cgu::swap
void swap(Cgu::AsyncQueue< T, Container > &q1, Cgu::AsyncQueue< T, Container > &q2)
Definition: async_queue.h:784
Cgu::IntrusivePtr::IntrusivePtr
IntrusivePtr(T *ptr=0)
Definition: intrusive_ptr.h:127
Cgu::IntrusivePtr::IntrusivePtr
IntrusivePtr(const IntrusivePtr &intr_ptr)
Definition: intrusive_ptr.h:139
Cgu::IntrusiveCounter::IntrusiveCounter
IntrusiveCounter()
Definition: intrusive_ptr.h:276
Cgu::IntrusivePtr::operator=
IntrusivePtr & operator=(IntrusivePtr intr_ptr)
Definition: intrusive_ptr.h:170
Cgu::IntrusivePtr::IntrusivePtr
IntrusivePtr(const IntrusivePtr< U > &intr_ptr)
Definition: intrusive_ptr.h:156
Cgu::IntrusivePtr::operator=
IntrusivePtr & operator=(const IntrusivePtr< U > &intr_ptr)
Definition: intrusive_ptr.h:184
Cgu::IntrusivePtr::get
T * get() const
Definition: intrusive_ptr.h:193
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::IntrusivePtr::IntrusivePtr
friend class IntrusivePtr
Definition: intrusive_ptr.h:144
Cgu::IntrusiveCounter::~IntrusiveCounter
virtual ~IntrusiveCounter()
Definition: intrusive_ptr.h:282
Cgu::IntrusiveLockCounter
This is a counter class providing the ref() and unref() functions required by IntrusivePtr,...
Definition: intrusive_ptr.h:317
mutex.h
Provides wrapper classes for pthread mutexes and condition variables, and scoped locking classes for ...
Cgu::operator==
bool operator==(const GobjHandle< T > &h1, const GobjHandle< T > &h2)
Definition: gobj_handle.h:602
Cgu::IntrusiveCounter::unref
void unref()
Definition: intrusive_ptr.h:268
Cgu::Thread::Mutex::unlock
int unlock()
Definition: mutex.h:155
Cgu::IntrusivePtr::~IntrusivePtr
~IntrusivePtr()
Definition: intrusive_ptr.h:228
Cgu::Thread::Mutex
A wrapper class for pthread mutexes.
Definition: mutex.h:109
cgu_config.h
Cgu::IntrusiveLockCounter::IntrusiveLockCounter
IntrusiveLockCounter()
Definition: intrusive_ptr.h:382
Cgu::IntrusivePtr::reset
void reset(T *ptr=0)
Definition: intrusive_ptr.h:219