c++-gtk-utils: shared_ptr.h Source File

c++-gtk-utils

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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