c++-gtk-utils
|
00001 /* Copyright (C) 2004 to 2011 Chris Vine 00002 00003 The library comprised in this file or of which this file is part is 00004 distributed by Chris Vine under the GNU Lesser General Public 00005 License as follows: 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Lesser General Public License 00009 as published by the Free Software Foundation; either version 2.1 of 00010 the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, but 00013 WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Lesser General Public License, version 2.1, for more details. 00016 00017 You should have received a copy of the GNU Lesser General Public 00018 License, version 2.1, along with this library (see the file LGPL.TXT 00019 which came with this source code package in the c++-gtk-utils 00020 sub-directory); if not, write to the Free Software Foundation, Inc., 00021 59 Temple Place - Suite 330, Boston, MA, 02111-1307, USA. 00022 00023 However, it is not intended that the object code of a program whose 00024 source code instantiates a template from this file or uses macros or 00025 inline functions (of any length) should by reason only of that 00026 instantiation or use be subject to the restrictions of use in the GNU 00027 Lesser General Public License. With that in mind, the words "and 00028 macros, inline functions and instantiations of templates (of any 00029 length)" shall be treated as substituted for the words "and small 00030 macros and small inline functions (ten lines or less in length)" in 00031 the fourth paragraph of section 5 of that licence. This does not 00032 affect any other reason why object code may be subject to the 00033 restrictions in that licence (nor for the avoidance of doubt does it 00034 affect the application of section 2 of that licence to modifications 00035 of the source code in this file). 00036 00037 */ 00038 00039 #ifndef CGU_SHARED_PTR_H 00040 #define CGU_SHARED_PTR_H 00041 00042 // define this if, instead of GLIB atomic funcions/memory barriers, 00043 // you want to use a (slower) mutex to lock the reference count in the 00044 // SharedLockPtr class (however, if wanted, this is best left for 00045 // definition in the user code) 00046 /* #define CGU_SHARED_LOCK_PTR_USE_MUTEX 1 */ 00047 00048 #include <utility> // for std::move and std::swap 00049 #include <exception> 00050 #include <new> 00051 #include <functional> // for std::less and std::hash<T*> 00052 #include <cstddef> // for std::size_t 00053 00054 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00055 #include <c++-gtk-utils/mutex.h> 00056 #else 00057 #include <glib.h> 00058 #endif 00059 00060 #include <c++-gtk-utils/cgu_config.h> 00061 00062 /** 00063 * @addtogroup handles handles and smart pointers 00064 */ 00065 00066 namespace Cgu { 00067 00068 /** 00069 * @class SharedPtrError shared_ptr.h c++-gtk-utils/shared_ptr.h 00070 * @brief This is an exception struct thrown as an alternative to 00071 * deleting a managed object when internal memory allocation for 00072 * SharedPtr or SharedLockPtr fails in their reset() method or in 00073 * their constructor which takes a pointer. 00074 * @ingroup handles 00075 * @sa SharedPtr SharedLockPtr SharedPtrAllocFail 00076 * 00077 * This is an exception struct thrown as an alternative to deleting a 00078 * managed object when SharedPtr<T>::SharedPtr(T*), 00079 * SharedLockPtr<T>::SharedLockPtr(T*), SharedPtr<T>::reset(T*) or 00080 * SharedLockPtr<T>::reset(T*), would otherwise throw std::bad_alloc. 00081 * To make those methods do that, Cgu::SharedPtrAllocFail::leave is 00082 * passed as their second argument. 00083 * 00084 * If the exception is thrown, the struct has a member 'obj' of type 00085 * T*, which is a pointer to the object originally passed to those 00086 * methods, so the user can deal with it appropriately. This enables 00087 * the result of the new expression to be passed directly as the 00088 * argument to those methods without giving rise to a resource leak, 00089 * as in: 00090 * 00091 * @code 00092 * using namespace Cgu; 00093 * SharedPtr<T> s; // doesn't throw 00094 * try { 00095 * s.reset(new T, SharedPtrAllocFail::leave); // both T allocation and reset() might throw 00096 * } 00097 * catch (std::bad_alloc&) { 00098 * ... 00099 * } 00100 * catch (SharedPtrError<T>& e) { 00101 * e.obj->do_something(); 00102 * ... 00103 * } 00104 * ... 00105 * @endcode 00106 * 00107 * As above, a catch block will need to deal with std::bad_alloc (if 00108 * the call to the new expression when creating the T object fails) 00109 * as well as SharedPtrError (if the call to the new expression in 00110 * the reset() method fails after a valid T object has been 00111 * constructed). 00112 */ 00113 00114 template <class T> struct SharedPtrError: public std::exception { 00115 T* obj; 00116 virtual const char* what() const throw() {return "SharedPtrError\n";} 00117 SharedPtrError(T* p): obj(p) {} 00118 }; 00119 00120 /** 00121 * enum Cgu::SharedPtrAllocFail::Leave 00122 * The enumerator Cgu::SharedPtrAllocFail::leave is passed as the 00123 * second argument of the reset() method of SharedPtr or 00124 * SharedLockPtr, or in their constructor which takes a pointer, in 00125 * order to prevent the method deleting the object passed to it if 00126 * reset() fails internally because of memory exhaustion. 00127 * @ingroup handles 00128 */ 00129 namespace SharedPtrAllocFail { 00130 enum Leave {leave}; 00131 } 00132 00133 00134 /** 00135 * @class SharedPtr shared_ptr.h c++-gtk-utils/shared_ptr.h 00136 * @brief This is a smart pointer for managing the lifetime of objects 00137 * allocated on freestore. 00138 * @ingroup handles 00139 * @sa SharedLockPtr SharedPtrError 00140 * 00141 * This is a smart pointer for managing the lifetime of objects 00142 * allocated on freestore with the new expression. A managed object 00143 * will be deleted when the last SharedPtr referencing it is 00144 * destroyed. 00145 * 00146 * @b Comparison @b with @b std::shared_ptr 00147 * 00148 * Most of the things that can be done by this class can be done by 00149 * using std::shared_ptr in C++11, but this class is retained in the 00150 * c++-gtk-utils library not only to retain compatibility with series 00151 * 1.2 of the library, but also to cater for some cases not met (or 00152 * not so easily met) by std::shared_ptr: 00153 * 00154 * (i) Glib memory slices provide an efficient small object allocator 00155 * (they are likely to be significantly more efficient than global 00156 * operator new()/new[](), which generally hands off to malloc(), and 00157 * whilst malloc() is good for large block allocations it is generally 00158 * poor as a small object allocator). Internal Cgu::SharedPtr 00159 * allocation using glib memory slices can be achieved simply by 00160 * compiling the library with the --with-glib-memory-slices-no-compat 00161 * configuration option. To use glib memory slices for internal 00162 * allocation within std::shared_ptr, a custom allocator object would 00163 * need to be passed to the shared_ptr constructor on every occasion a 00164 * shared_ptr is constructed to manage a new object (and it cannot be 00165 * templated as a typedef for convenient construction). 00166 * 00167 * (ii) If glib memory slices are not used (which do not throw), 00168 * constructing a shared pointer for a new managed object (or calling 00169 * reset() for a new managed object) might throw if internal 00170 * allocation fails. Although by default the Cgu::SharedPtr 00171 * implementation will delete the new managed object in such a case, 00172 * it also provides an alternative constructor and reset() method 00173 * which instead enables the new object to be accessed via the thrown 00174 * exception object so that user code can decide what to do; 00175 * std::shared_ptr deletes the new object in every case. 00176 * 00177 * (iii) A user can explicitly state whether the shared pointer object 00178 * is to have atomic increment and decrement-and-test with respect to 00179 * the reference count so that the reference count is thread safe 00180 * ('no' in the case of Cgu::SharedPtr, and 'yes' in the case of 00181 * Cgu::SharedLockPtr). Using atomic functions is unnecessary if the 00182 * managed object concerned is only addressed in one thread (and might 00183 * cause unwanted cache flushing in certain circumstances). 00184 * std::shared_ptr will generally always use atomic functions with 00185 * respect to its reference count in a multi-threaded program. 00186 * 00187 * In favour of std::shared_ptr, it has an associated std::weak_ptr 00188 * class, which Cgu::SharedPtr does not (there is a 00189 * Cgu::GobjWeakHandle class, but that is cognate with Cgu::GobjHandle 00190 * and is only usable with GObjects). 00191 */ 00192 00193 template <class T> class SharedPtr { 00194 00195 #ifndef DOXYGEN_PARSING 00196 struct RefItems { 00197 unsigned int* ref_count_p; 00198 T* obj_p; 00199 } ref_items; 00200 #endif 00201 00202 void unreference() { 00203 if (!ref_items.ref_count_p) return; 00204 --(*ref_items.ref_count_p); 00205 if (*ref_items.ref_count_p == 0) { 00206 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT 00207 g_slice_free(unsigned int, ref_items.ref_count_p); 00208 #else 00209 delete ref_items.ref_count_p; 00210 #endif 00211 delete ref_items.obj_p; 00212 } 00213 } 00214 00215 void reference() { 00216 if (!ref_items.ref_count_p) return; 00217 ++(*ref_items.ref_count_p); 00218 } 00219 00220 public: 00221 /** 00222 * Constructor taking an unmanaged object. 00223 * @param ptr The object which the SharedPtr is to manage (if any). 00224 * @exception std::bad_alloc This constructor will not throw if the 00225 * 'ptr' argument has a NULL value (the default), otherwise it might 00226 * throw std::bad_alloc if memory is exhausted and the system throws 00227 * in that case. If such an exception is thrown, this constructor is 00228 * exception safe (it does not leak resources), but as well as 00229 * cleaning itself up this constructor will also delete the managed 00230 * object passed to it to avoid a memory leak. If such automatic 00231 * deletion is not wanted in that case, use the version of this 00232 * constructor taking a Cgu::SharedPtrAllocFail::Leave tag argument. 00233 * @note std::bad_alloc will not be thrown if the library has been 00234 * installed using the --with-glib-memory-slices-no-compat 00235 * configuration option: instead glib will terminate the program if it 00236 * is unable to obtain memory from the operating system. 00237 */ 00238 explicit SharedPtr(T* ptr = 0) { 00239 00240 if ((ref_items.obj_p = ptr)) { // not NULL 00241 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT 00242 ref_items.ref_count_p = g_slice_new(unsigned int); 00243 *ref_items.ref_count_p = 1; 00244 #else 00245 try { 00246 ref_items.ref_count_p = new unsigned int(1); 00247 } 00248 catch (...) { 00249 delete ptr; // if allocating the int referenced by ref_items.ref_count_p 00250 // has failed then delete the object to be referenced to 00251 // avoid a memory leak 00252 throw; 00253 } 00254 #endif 00255 } 00256 else ref_items.ref_count_p = 0; 00257 } 00258 00259 /** 00260 * Constructor taking an unmanaged object. 00261 * @param ptr The object which the SharedPtr is to manage. 00262 * @param tag Passing the tag emumerator 00263 * Cgu::SharedPtrAllocFail::leave causes this constructor not to 00264 * delete the new managed object passed as the 'ptr' argument in the 00265 * event of internal allocation in this method failing because of 00266 * memory exhaustion (in that event, Cgu::SharedPtrError will be 00267 * thrown). 00268 * @exception Cgu::SharedPtrError This constructor might throw 00269 * Cgu::SharedPtrError if memory is exhausted and the system would 00270 * otherwise throw std::bad_alloc in that case. This constructor is 00271 * exception safe (it does not leak resources), and if such an 00272 * exception is thrown it will clean itself up, but it will not 00273 * attempt to delete the new managed object passed to it. Access to 00274 * the object passed to the 'ptr' argument can be obtained via the 00275 * thrown Cgu::SharedPtrError object. 00276 * @note 1. On systems with over-commit/lazy-commit combined with 00277 * virtual memory (swap), it is rarely useful to check for memory 00278 * exhaustion, so in those cases this version of the constructor will 00279 * not be useful. 00280 * @note 2. If the library has been installed using the 00281 * --with-glib-memory-slices-no-compat configuration option this 00282 * version of the constructor will also not be useful: instead glib 00283 * will terminate the program if it is unable to obtain memory from 00284 * the operating system. 00285 */ 00286 SharedPtr(T* ptr, Cgu::SharedPtrAllocFail::Leave tag) { 00287 00288 if ((ref_items.obj_p = ptr)) { // not NULL 00289 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT 00290 ref_items.ref_count_p = g_slice_new(unsigned int); 00291 *ref_items.ref_count_p = 1; 00292 #else 00293 try { 00294 ref_items.ref_count_p = new unsigned int(1); 00295 } 00296 catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly 00297 throw SharedPtrError<T>(ptr); 00298 } 00299 #endif 00300 } 00301 else ref_items.ref_count_p = 0; 00302 } 00303 00304 /** 00305 * Causes the SharedPtr to cease to manage its managed object (if 00306 * any), deleting it if this is the last SharedPtr object managing it. 00307 * If the argument passed is not NULL, the SharedPtr object will 00308 * manage the new object passed (which must not be managed by any 00309 * other SharedPtr object). This method is exception safe, but see 00310 * the comments below on std::bad_alloc. 00311 * @param ptr NULL (the default), or a new unmanaged object to manage. 00312 * @exception std::bad_alloc This method will not throw if the 'ptr' 00313 * argument has a NULL value (the default) and the destructor of a 00314 * managed object does not throw, otherwise it might throw 00315 * std::bad_alloc if memory is exhausted and the system throws in that 00316 * case. Note that if such an exception is thrown then this method 00317 * will do nothing (it is strongly exception safe and will continue to 00318 * manage the object it was managing prior to the call), except that 00319 * it will delete the new managed object passed to it to avoid a 00320 * memory leak. If such automatic deletion in the event of such an 00321 * exception is not wanted, use the reset() method taking a 00322 * Cgu::SharedPtrAllocFail::Leave tag type as its second argument. 00323 * @note std::bad_alloc will not be thrown if the library has been 00324 * installed using the --with-glib-memory-slices-no-compat 00325 * configuration option: instead glib will terminate the program if it 00326 * is unable to obtain memory from the operating system. 00327 */ 00328 void reset(T* ptr = 0) { 00329 SharedPtr tmp(ptr); 00330 std::swap(ref_items, tmp.ref_items); 00331 } 00332 00333 /** 00334 * Causes the SharedPtr to cease to manage its managed object (if 00335 * any), deleting it if this is the last SharedPtr object managing it. 00336 * The SharedPtr object will manage the new object passed (which must 00337 * not be managed by any other SharedPtr object). This method is 00338 * exception safe, but see the comments below on Cgu::SharedPtrError. 00339 * @param ptr A new unmanaged object to manage (if no new object is to 00340 * be managed, use the version of reset() taking a default value of 00341 * NULL). 00342 * @param tag Passing the tag emumerator 00343 * Cgu::SharedPtrAllocFail::leave causes this method not to delete the 00344 * new managed object passed as the 'ptr' argument in the event of 00345 * internal allocation in this method failing because of memory 00346 * exhaustion (in that event, Cgu::SharedPtrError will be thrown). 00347 * @exception Cgu::SharedPtrError This method might throw 00348 * Cgu::SharedPtrError if memory is exhausted and the system would 00349 * otherwise throw std::bad_alloc in that case. Note that if such an 00350 * exception is thrown then this method will do nothing (it is 00351 * strongly exception safe and will continue to manage the object it 00352 * was managing prior to the call), and it will not attempt to delete 00353 * the new managed object passed to it. Access to the object passed 00354 * to the 'ptr' argument can be obtained via the thrown 00355 * Cgu::SharedPtrError object. 00356 * @note 1. On systems with over-commit/lazy-commit combined with 00357 * virtual memory (swap), it is rarely useful to check for memory 00358 * exhaustion, so in those cases this version of the reset() method 00359 * will not be useful. 00360 * @note 2. If the library has been installed using the 00361 * --with-glib-memory-slices-no-compat configuration option this 00362 * version of the reset() method will also not be useful: instead glib 00363 * will terminate the program if it is unable to obtain memory from 00364 * the operating system. 00365 */ 00366 void reset(T* ptr, Cgu::SharedPtrAllocFail::Leave tag) { 00367 SharedPtr tmp(ptr, tag); 00368 std::swap(ref_items, tmp.ref_items); 00369 } 00370 00371 /** 00372 * This copy constructor does not throw. 00373 * @param sh_ptr The shared pointer to be copied. 00374 */ 00375 SharedPtr(const SharedPtr& sh_ptr) { 00376 ref_items = sh_ptr.ref_items; 00377 reference(); 00378 } 00379 00380 /** 00381 * The move constructor does not throw. It has move semantics. 00382 * @param sh_ptr The shared pointer to be moved. 00383 */ 00384 SharedPtr(SharedPtr&& sh_ptr) { 00385 ref_items = sh_ptr.ref_items; 00386 sh_ptr.ref_items.ref_count_p = 0; 00387 sh_ptr.ref_items.obj_p = 0; 00388 } 00389 00390 template <class U> friend class SharedPtr; 00391 00392 /** 00393 * A version of the copy constructor which enables pointer type 00394 * conversion (assuming the type passed is implicitly type 00395 * convertible to the managed type, such as a derived type). This 00396 * copy constructor does not throw. 00397 * @param sh_ptr The shared pointer to be copied. 00398 */ 00399 template <class U> SharedPtr(const SharedPtr<U>& sh_ptr) { 00400 // because we are allowing an implicit cast from derived to 00401 // base class referenced object, we need to assign from each 00402 // member of sh_ptr.ref_items separately 00403 ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p; 00404 ref_items.obj_p = sh_ptr.ref_items.obj_p; 00405 reference(); 00406 } 00407 00408 /** 00409 * A version of the move constructor which enables pointer type 00410 * conversion (assuming the type passed is implicitly type 00411 * convertible to the managed type, such as a derived type). This 00412 * move constructor does not throw. 00413 * @param sh_ptr The shared pointer to be moved. 00414 */ 00415 template <class U> SharedPtr(SharedPtr<U>&& sh_ptr) { 00416 // because we are allowing an implicit cast from derived to 00417 // base class referenced object, we need to assign from each 00418 // member of sh_ptr.ref_items separately 00419 ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p; 00420 ref_items.obj_p = sh_ptr.ref_items.obj_p; 00421 sh_ptr.ref_items.ref_count_p = 0; 00422 sh_ptr.ref_items.obj_p = 0; 00423 } 00424 00425 /** 00426 * This method (and so copy or move assignment) does not throw unless 00427 * the destructor of a managed object throws. 00428 * @param sh_ptr the assignor. 00429 * @return The SharedPtr object after assignment. 00430 */ 00431 // having a value type as the argument, rather than reference to const 00432 // and then initialising a tmp object, gives the compiler more scope 00433 // for optimisation, and also caters for r-values without a separate 00434 // overload 00435 SharedPtr& operator=(SharedPtr sh_ptr) { 00436 std::swap(ref_items, sh_ptr.ref_items); 00437 return *this; 00438 } 00439 00440 /** 00441 * A version of the assignment operator which enables pointer type 00442 * conversion (assuming the type passed is implicitly type 00443 * convertible to the managed type, such as a derived type). This 00444 * method does not throw unless the destructor of a managed object 00445 * throws. 00446 * @param sh_ptr the assignor. 00447 * @return The SharedPtr object after assignment. 00448 */ 00449 template <class U> SharedPtr& operator=(const SharedPtr<U>& sh_ptr) { 00450 return operator=(SharedPtr(sh_ptr)); 00451 } 00452 00453 /** 00454 * A version of the operator for move assignment which enables 00455 * pointer type conversion (assuming the type passed is implicitly 00456 * type convertible to the managed type, such as a derived type). 00457 * This method does not throw unless the destructor of a managed 00458 * object throws. 00459 * @param sh_ptr the shared pointer to be moved. 00460 * @return The SharedPtr object after the move operation. 00461 */ 00462 template <class U> SharedPtr& operator=(SharedPtr<U>&& sh_ptr) { 00463 return operator=(SharedPtr(std::move(sh_ptr))); 00464 } 00465 00466 /** 00467 * This method does not throw. 00468 * @return A pointer to the managed object (or NULL if none is 00469 * managed). 00470 */ 00471 T* get() const {return ref_items.obj_p;} 00472 00473 /** 00474 * This method does not throw. 00475 * @return A reference to the managed object. 00476 */ 00477 T& operator*() const {return *ref_items.obj_p;} 00478 00479 /** 00480 * This method does not throw. 00481 * @return A pointer to the managed object (or NULL if none is 00482 * managed). 00483 */ 00484 T* operator->() const {return ref_items.obj_p;} 00485 00486 /** 00487 * This method does not throw. 00488 * @return The number of SharedPtr objects referencing the managed 00489 * object (or 0 if none is managed by this SharedPtr). 00490 */ 00491 unsigned int get_refcount() const {return (ref_items.ref_count_p) ? *ref_items.ref_count_p : 0;} 00492 00493 /** 00494 * The destructor does not throw unless the destructor of a managed 00495 * object throws - that should never happen. 00496 */ 00497 ~SharedPtr() {unreference();} 00498 }; 00499 00500 /** 00501 * @class SharedLockPtr shared_ptr.h c++-gtk-utils/shared_ptr.h 00502 * @brief This is a smart pointer for managing the lifetime of objects 00503 * allocated on freestore, with a thread safe reference count. 00504 * @ingroup handles 00505 * @sa SharedPtr SharedPtrError 00506 * 00507 * Class SharedLockPtr is a version of the shared pointer class which 00508 * includes locking so that it can be accessed in multiple threads 00509 * (although the word Lock is in the title, by default it uses glib 00510 * atomic functions to access the reference count rather than a mutex, 00511 * so the overhead should be very small). Note that only the 00512 * reference count is protected, so this is thread safe in the sense 00513 * in which a raw pointer is thread safe. A shared pointer accessed 00514 * in one thread referencing a particular object is thread safe as 00515 * against another shared pointer accessing the same object in a 00516 * different thread. It is thus suitable for use in different Std C++ 00517 * containers which exist in different threads but which contain 00518 * shared objects by reference. But: 00519 * 00520 * 1. If the referenced object is to be modified in one thread and 00521 * read or modified in another thread an appropriate mutex for the 00522 * referenced object is required (unless that referenced object 00523 * does its own locking). 00524 * 00525 * 2. If the same instance of shared pointer is to be modified in one 00526 * thread (by assigning to the pointer so that it references a 00527 * different object), and copied (assigned from or used as the 00528 * argument of a copy constructor) or modified in another thread, 00529 * a mutex for that instance of shared pointer is required. 00530 * 00531 * 3. Objects referenced by shared pointers which are objects for 00532 * which POSIX provides no guarantees (in the main, those which 00533 * are not built-in types), such as strings and similar 00534 * containers, may not support concurrent reads in different 00535 * threads. That depends on the library implementation concerned. 00536 * If that is the case, a mutex for the referenced object will 00537 * also be required when reading any given instance of such an 00538 * object in more than one thread by dereferencing any shared 00539 * pointers referencing it (and indeed, when not using shared 00540 * pointers at all). 00541 * 00542 * As mentioned, by default glib atomic functions are used to provide 00543 * thread-safe manipulation of the reference count. However, a 00544 * library user can define the symbol CGU_SHARED_LOCK_PTR_USE_MUTEX 00545 * before shared_ptr.h is parsed so as to use mutexes instead, which 00546 * might be useful for some debugging purposes. 00547 * 00548 * @b Comparison @b with @b std::shared_ptr 00549 * 00550 * Most of the things that can be done by this class can be done by 00551 * using std::shared_ptr in C++11, but this class is retained in the 00552 * c++-gtk-utils library not only to retain compatibility with series 00553 * 1.2 of the library, but also to cater for some cases not met (or 00554 * not so easily met) by std::shared_ptr: 00555 * 00556 * (i) Glib memory slices provide an efficient small object allocator 00557 * (they are likely to be significantly more efficient than global 00558 * operator new()/new[](), which generally hands off to malloc(), and 00559 * whilst malloc() is good for large block allocations it is generally 00560 * poor as a small object allocator). Internal Cgu::SharedLockPtr 00561 * allocation using glib memory slices can be achieved simply by 00562 * compiling the library with the --with-glib-memory-slices-no-compat 00563 * configuration option. To use glib memory slices for internal 00564 * allocation within std::shared_ptr, a custom allocator object would 00565 * need to be passed to the shared_ptr constructor on every occasion a 00566 * shared_ptr is constructed to manage a new object (and it cannot be 00567 * templated as a typedef for convenient construction). 00568 * 00569 * (ii) If glib memory slices are not used (which do not throw), 00570 * constructing a shared pointer for a new managed object (or calling 00571 * reset() for a new managed object) might throw if internal 00572 * allocation fails. Although by default the Cgu::SharedLockPtr 00573 * implementation will delete the new managed object in such a case, 00574 * it also provides an alternative constructor and reset() method 00575 * which instead enables the new object to be accessed via the thrown 00576 * exception object so that user code can decide what to do; 00577 * std::shared_ptr deletes the new object in every case. 00578 * 00579 * (iii) A user can explicitly state whether the shared pointer object 00580 * is to have atomic increment and decrement-and-test with respect to 00581 * the reference count so that the reference count is thread safe 00582 * ('no' in the case of Cgu::SharedPtr, and 'yes' in the case of 00583 * Cgu::SharedLockPtr). Using atomic functions is unnecessary if the 00584 * managed object concerned is only addressed in one thread (and might 00585 * cause unwanted cache flushing in certain circumstances). 00586 * std::shared_ptr will generally always use atomic functions with 00587 * respect to its reference count in a multi-threaded program. 00588 * 00589 * In favour of std::shared_ptr, it has an associated std::weak_ptr 00590 * class, which Cgu::SharedLockPtr does not (there is a 00591 * Cgu::GobjWeakHandle class, but that is cognate with Cgu::GobjHandle 00592 * and is only usable with GObjects). In addition shared_ptr objects 00593 * have some atomic store, load and exchange functions provided for 00594 * them which enable concurrent modifications of the same instance of 00595 * shared_ptr in different threads to have defined results. 00596 */ 00597 00598 template <class T> class SharedLockPtr { 00599 00600 #ifndef DOXYGEN_PARSING 00601 struct RefItems { 00602 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00603 Thread::Mutex* mutex_p; 00604 unsigned int* ref_count_p; 00605 #else 00606 gint* ref_count_p; 00607 #endif 00608 T* obj_p; 00609 } ref_items; 00610 #endif 00611 00612 // SharedLockPtr<T>::unreference() does not throw if the destructor of the 00613 // contained object does not throw, because Thread::Mutex::~Mutex(), 00614 // Thread::Mutex::lock() and Thread::Mutex::unlock() do not throw 00615 void unreference() { 00616 // we can (and should) check whether ref_items.ref_count_p is NULL without 00617 // a lock, because that member is specific to this SharedLockPtr object. 00618 // Only the integer pointed to by it is shared amongst SharedLockPtr 00619 // objects and requires locking 00620 if (!ref_items.ref_count_p) return; 00621 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00622 ref_items.mutex_p->lock(); 00623 --(*ref_items.ref_count_p); 00624 if (*ref_items.ref_count_p == 0) { 00625 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT 00626 g_slice_free(unsigned int, ref_items.ref_count_p); 00627 # else 00628 delete ref_items.ref_count_p; 00629 # endif 00630 ref_items.mutex_p->unlock(); 00631 delete ref_items.mutex_p; 00632 delete ref_items.obj_p; 00633 } 00634 else ref_items.mutex_p->unlock(); 00635 #else 00636 if (g_atomic_int_dec_and_test(ref_items.ref_count_p)) { 00637 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT 00638 g_slice_free(gint, ref_items.ref_count_p); 00639 # else 00640 delete ref_items.ref_count_p; 00641 # endif 00642 delete ref_items.obj_p; 00643 } 00644 #endif 00645 } 00646 00647 // SharedLockPtr<T>::reference() does not throw because 00648 // Thread::Mutex::Lock::Lock() and Thread::Mutex::Lock::~Lock() do not throw 00649 void reference() { 00650 // we can (and should) check whether ref_items.ref_count_p is NULL without 00651 // a lock, because that member is specific to this SharedLockPtr object. 00652 // Only the integer pointed to by it is shared amongst SharedLockPtr 00653 // objects and requires locking 00654 if (!ref_items.ref_count_p) return; 00655 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00656 Thread::Mutex::Lock lock(*ref_items.mutex_p); 00657 ++(*ref_items.ref_count_p); 00658 #else 00659 g_atomic_int_inc(ref_items.ref_count_p); 00660 #endif 00661 } 00662 00663 public: 00664 /** 00665 * Constructor taking an unmanaged object. 00666 * @param ptr The object which the SharedLockPtr is to manage (if 00667 * any). 00668 * @exception std::bad_alloc This constructor will not throw if the 00669 * 'ptr' argument has a NULL value (the default), otherwise it might 00670 * throw std::bad_alloc if memory is exhausted and the system throws 00671 * in that case. If such an exception is thrown, this constructor is 00672 * exception safe (it does not leak resources), but as well as 00673 * cleaning itself up this constructor will also delete the managed 00674 * object passed to it to avoid a memory leak. If such automatic 00675 * deletion is not wanted in that case, use the version of this 00676 * constructor taking a Cgu::SharedPtrAllocFail::Leave tag argument. 00677 * @note 1. std::bad_alloc will not be thrown if the library has been 00678 * installed using the --with-glib-memory-slices-no-compat 00679 * configuration option: instead glib will terminate the program if it 00680 * is unable to obtain memory from the operating system. 00681 * @note 2. By default, glib atomic functions are used to provide 00682 * thread-safe manipulation of the reference count. However, a 00683 * library user can define the symbol CGU_SHARED_LOCK_PTR_USE_MUTEX 00684 * before shared_ptr.h is parsed so as to use mutexes instead, which 00685 * might be useful for some debugging purposes. Were she to do so, 00686 * Cgu::Thread::MutexError might be thrown by this constructor if 00687 * initialization of the mutex fails, but it is usually not worth 00688 * checking for this. 00689 */ 00690 explicit SharedLockPtr(T* ptr = 0) { 00691 00692 if ((ref_items.obj_p = ptr)) { // not NULL 00693 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00694 try { 00695 ref_items.mutex_p = new Thread::Mutex; 00696 } 00697 catch (...) { 00698 delete ptr; // if allocating the object referenced by ref_items.mutex_p 00699 // has failed then delete the object to be referenced to 00700 // avoid a memory leak 00701 throw; 00702 } 00703 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT 00704 ref_items.ref_count_p = g_slice_new(unsigned int); 00705 *ref_items.ref_count_p = 1; 00706 # else 00707 try { 00708 ref_items.ref_count_p = new unsigned int(1); 00709 } 00710 catch (...) { 00711 delete ref_items.mutex_p; 00712 delete ptr; 00713 throw; 00714 } 00715 # endif 00716 #else 00717 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT 00718 ref_items.ref_count_p = g_slice_new(gint); 00719 *ref_items.ref_count_p = 1; 00720 # else 00721 try { 00722 ref_items.ref_count_p = new gint(1); 00723 } 00724 catch (...) { 00725 delete ptr; // if allocating the int referenced by ref_items.ref_count_p 00726 // has failed then delete the object to be referenced to 00727 // avoid a memory leak 00728 throw; 00729 } 00730 # endif 00731 #endif 00732 } 00733 else { 00734 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00735 ref_items.mutex_p = 0; // make sure the value is valid as we may assign it 00736 #endif 00737 ref_items.ref_count_p = 0; 00738 } 00739 } 00740 00741 /** 00742 * Constructor taking an unmanaged object. 00743 * @param ptr The object which the SharedLockPtr is to manage. 00744 * @param tag Passing the tag emumerator 00745 * Cgu::SharedPtrAllocFail::leave causes this constructor not to 00746 * delete the new managed object passed as the 'ptr' argument in the 00747 * event of internal allocation in this method failing because of 00748 * memory exhaustion (in that event, Cgu::SharedPtrError will be 00749 * thrown). 00750 * @exception Cgu::SharedPtrError This constructor might throw 00751 * Cgu::SharedPtrError if memory is exhausted and the system would 00752 * otherwise throw std::bad_alloc in that case. This constructor is 00753 * exception safe (it does not leak resources), and if such an 00754 * exception is thrown it will clean itself up, but it will not 00755 * attempt to delete the new managed object passed to it. Access to 00756 * the object passed to the 'ptr' argument can be obtained via the 00757 * thrown Cgu::SharedPtrError object. 00758 * @note 1. On systems with over-commit/lazy-commit combined with 00759 * virtual memory (swap), it is rarely useful to check for memory 00760 * exhaustion, so in those cases this version of the constructor will 00761 * not be useful. 00762 * @note 2. If the library has been installed using the 00763 * --with-glib-memory-slices-no-compat configuration option this 00764 * version of the constructor will also not be useful: instead glib 00765 * will terminate the program if it is unable to obtain memory from 00766 * the operating system. 00767 * @note 3. By default, glib atomic functions are used to provide 00768 * thread-safe manipulation of the reference count. However, a 00769 * library user can define the symbol CGU_SHARED_LOCK_PTR_USE_MUTEX 00770 * before shared_ptr.h is parsed so as to use mutexes instead, which 00771 * might be useful for some debugging purposes. Were she to do so, 00772 * Cgu::SharedPtrError might be thrown by this constructor if 00773 * initialization of the mutex fails (even if the 00774 * --with-glib-memory-slices-no-compat configuration option is 00775 * chosen), but it is usually not worth checking for such mutex 00776 * initialization failure. 00777 */ 00778 SharedLockPtr(T* ptr, Cgu::SharedPtrAllocFail::Leave tag) { 00779 00780 if ((ref_items.obj_p = ptr)) { // not NULL 00781 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00782 try { 00783 ref_items.mutex_p = new Thread::Mutex; 00784 } 00785 catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly 00786 throw SharedPtrError<T>(ptr); 00787 } 00788 catch (Thread::MutexError&) { // as we are not rethrowing, make NPTL friendly 00789 throw SharedPtrError<T>(ptr); 00790 } 00791 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT 00792 ref_items.ref_count_p = g_slice_new(unsigned int); 00793 *ref_items.ref_count_p = 1; 00794 # else 00795 try { 00796 ref_items.ref_count_p = new unsigned int(1); 00797 } 00798 catch (std::bad_alloc&) { 00799 delete ref_items.mutex_p; 00800 throw SharedPtrError<T>(ptr); 00801 } 00802 # endif 00803 #else 00804 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT 00805 ref_items.ref_count_p = g_slice_new(gint); 00806 *ref_items.ref_count_p = 1; 00807 # else 00808 try { 00809 ref_items.ref_count_p = new gint(1); 00810 } 00811 catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly 00812 throw SharedPtrError<T>(ptr); 00813 } 00814 # endif 00815 #endif 00816 } 00817 else { 00818 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00819 ref_items.mutex_p = 0; // make sure the value is valid as we may assign it 00820 #endif 00821 ref_items.ref_count_p = 0; 00822 } 00823 } 00824 00825 /** 00826 * Causes the SharedLockPtr to cease to manage its managed object (if 00827 * any), deleting it if this is the last SharedLockPtr object managing 00828 * it. If the argument passed is not NULL, the SharedLockPtr object 00829 * will manage the new object passed (which must not be managed by any 00830 * other SharedLockPtr object). This method is exception safe, but 00831 * see the comments below on std::bad_alloc. 00832 * @param ptr NULL (the default), or a new unmanaged object to manage. 00833 * @exception std::bad_alloc This method will not throw if the 'ptr' 00834 * argument has a NULL value (the default) and the destructor of a 00835 * managed object does not throw, otherwise it might throw 00836 * std::bad_alloc if memory is exhausted and the system throws in that 00837 * case. Note that if such an exception is thrown then this method 00838 * will do nothing (it is strongly exception safe and will continue to 00839 * manage the object it was managing prior to the call), except that 00840 * it will delete the new managed object passed to it to avoid a 00841 * memory leak. If such automatic deletion in the event of such an 00842 * exception is not wanted, use the reset() method taking a 00843 * Cgu::SharedPtrAllocFail::Leave tag type as its second argument. 00844 * @note 1. std::bad_alloc will not be thrown if the library has been 00845 * installed using the --with-glib-memory-slices-no-compat 00846 * configuration option: instead glib will terminate the program if it 00847 * is unable to obtain memory from the operating system. 00848 * @note 2. By default, glib atomic functions are used to provide 00849 * thread-safe manipulation of the reference count. However, a 00850 * library user can define the symbol CGU_SHARED_LOCK_PTR_USE_MUTEX 00851 * before shared_ptr.h is parsed so as to use mutexes instead, which 00852 * might be useful for some debugging purposes. Were she to do so, 00853 * Cgu::Thread::MutexError might be thrown by this method if 00854 * initialization of the mutex fails, but it is usually not worth 00855 * checking for this. 00856 * @note 3. A SharedLockPtr object protects its reference count but 00857 * not the managed object or its other internals. The reset() method 00858 * should not be called by one thread in respect of a particular 00859 * SharedLockPtr object while another thread may be operating on, 00860 * copying or dereferencing the same instance of SharedLockPtr. It is 00861 * thread-safe as against another instance of SharedLockPtr managing 00862 * the same object. 00863 */ 00864 void reset(T* ptr = 0) { 00865 SharedLockPtr tmp(ptr); 00866 std::swap(ref_items, tmp.ref_items); 00867 } 00868 00869 /** 00870 * Causes the SharedLockPtr to cease to manage its managed object (if 00871 * any), deleting it if this is the last SharedLockPtr object managing 00872 * it. The SharedLockPtr object will manage the new object passed 00873 * (which must not be managed by any other SharedLockPtr object). 00874 * This method is exception safe, but see the comments below on 00875 * Cgu::SharedPtrError. 00876 * @param ptr A new unmanaged object to manage (if no new object is to 00877 * be managed, use the version of reset() taking a default value of 00878 * NULL). 00879 * @param tag Passing the tag emumerator 00880 * Cgu::SharedPtrAllocFail::leave causes this method not to delete the 00881 * new managed object passed as the 'ptr' argument in the event of 00882 * internal allocation in this method failing because of memory 00883 * exhaustion (in that event, Cgu::SharedPtrError will be thrown). 00884 * @exception Cgu::SharedPtrError This method might throw 00885 * Cgu::SharedPtrError if memory is exhausted and the system would 00886 * otherwise throw std::bad_alloc in that case. Note that if such an 00887 * exception is thrown then this method will do nothing (it is 00888 * strongly exception safe and will continue to manage the object it 00889 * was managing prior to the call), and it will not attempt to delete 00890 * the new managed object passed to it. Access to the object passed 00891 * to the 'ptr' argument can be obtained via the thrown 00892 * Cgu::SharedPtrError object. 00893 * @note 1. A SharedLockPtr object protects its reference count but 00894 * not the managed object or its other internals. The reset() method 00895 * should not be called by one thread in respect of a particular 00896 * SharedLockPtr object while another thread may be operating on, 00897 * copying or dereferencing the same instance of SharedLockPtr. It is 00898 * thread-safe as against another instance of SharedLockPtr managing 00899 * the same object. 00900 * @note 2. On systems with over-commit/lazy-commit combined with 00901 * virtual memory (swap), it is rarely useful to check for memory 00902 * exhaustion, so in those cases this version of the reset() method 00903 * will not be useful. 00904 * @note 3. If the library has been installed using the 00905 * --with-glib-memory-slices-no-compat configuration option this 00906 * version of the reset() method will also not be useful: instead glib 00907 * will terminate the program if it is unable to obtain memory from 00908 * the operating system. 00909 * @note 4. By default, glib atomic functions are used to provide 00910 * thread-safe manipulation of the reference count. However, a 00911 * library user can define the symbol CGU_SHARED_LOCK_PTR_USE_MUTEX 00912 * before shared_ptr.h is parsed so as to use mutexes instead, which 00913 * might be useful for some debugging purposes. Were she to do so, 00914 * Cgu::SharedPtrError might be thrown by this method if 00915 * initialization of the mutex fails (even if the 00916 * --with-glib-memory-slices-no-compat configuration option is 00917 * chosen), but it is usually not worth checking for such mutex 00918 * initialization failure. 00919 */ 00920 void reset(T* ptr, Cgu::SharedPtrAllocFail::Leave tag) { 00921 SharedLockPtr tmp(ptr, tag); 00922 std::swap(ref_items, tmp.ref_items); 00923 } 00924 00925 /** 00926 * This copy constructor does not throw. 00927 * @param sh_ptr The shared pointer to be copied. 00928 */ 00929 SharedLockPtr(const SharedLockPtr& sh_ptr) { 00930 ref_items = sh_ptr.ref_items; 00931 reference(); 00932 } 00933 00934 /** 00935 * The move constructor does not throw. It has move semantics. 00936 * @param sh_ptr The shared pointer to be moved. 00937 */ 00938 SharedLockPtr(SharedLockPtr&& sh_ptr) { 00939 ref_items = sh_ptr.ref_items; 00940 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00941 sh_ptr.ref_items.mutex_p = 0; // make sure the value is valid as we may assign it 00942 #endif 00943 sh_ptr.ref_items.ref_count_p = 0; 00944 sh_ptr.ref_items.obj_p = 0; 00945 } 00946 00947 template <class U> friend class SharedLockPtr; 00948 00949 /** 00950 * A version of the copy constructor which enables pointer type 00951 * conversion (assuming the type passed is implicitly type 00952 * convertible to the managed type, such as a derived type). This 00953 * copy constructor does not throw. 00954 * @param sh_ptr The shared pointer to be copied. 00955 */ 00956 template <class U> SharedLockPtr(const SharedLockPtr<U>& sh_ptr) { 00957 // because we are allowing an implicit cast from derived to 00958 // base class referenced object, we need to assign from each 00959 // member of sh_ptr.ref_items separately 00960 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00961 ref_items.mutex_p = sh_ptr.ref_items.mutex_p; 00962 #endif 00963 ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p; 00964 ref_items.obj_p = sh_ptr.ref_items.obj_p; 00965 reference(); 00966 } 00967 00968 /** 00969 * A version of the move constructor which enables pointer type 00970 * conversion (assuming the type passed is implicitly type 00971 * convertible to the managed type, such as a derived type). This 00972 * move constructor does not throw. 00973 * @param sh_ptr The shared pointer to be moved. 00974 */ 00975 template <class U> SharedLockPtr(SharedLockPtr<U>&& sh_ptr) { 00976 // because we are allowing an implicit cast from derived to 00977 // base class referenced object, we need to assign from each 00978 // member of sh_ptr.ref_items separately 00979 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00980 ref_items.mutex_p = sh_ptr.ref_items.mutex_p; 00981 #endif 00982 ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p; 00983 ref_items.obj_p = sh_ptr.ref_items.obj_p; 00984 00985 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00986 sh_ptr.ref_items.mutex_p = 0; // make sure the value is valid as we may assign it 00987 #endif 00988 sh_ptr.ref_items.ref_count_p = 0; 00989 sh_ptr.ref_items.obj_p = 0; 00990 } 00991 00992 /** 00993 * This method (and so copy or move assignment) does not throw unless 00994 * the destructor of a managed object throws. 00995 * @param sh_ptr the assignor. 00996 * @return The SharedLockPtr object after assignment. 00997 */ 00998 // having a value type as the argument, rather than reference to const 00999 // and then initialising a tmp object, gives the compiler more scope 01000 // for optimisation, and also caters for r-values without a separate 01001 // overload 01002 SharedLockPtr& operator=(SharedLockPtr sh_ptr) { 01003 std::swap(ref_items, sh_ptr.ref_items); 01004 return *this; 01005 } 01006 01007 /** 01008 * A version of the assignment operator which enables pointer type 01009 * conversion (assuming the type passed is implicitly type 01010 * convertible to the managed type, such as a derived type). This 01011 * method does not throw unless the destructor of a managed object 01012 * throws. 01013 * @param sh_ptr the assignor. 01014 * @return The SharedLockPtr object after assignment. 01015 */ 01016 template <class U> SharedLockPtr& operator=(const SharedLockPtr<U>& sh_ptr) { 01017 return operator=(SharedLockPtr(sh_ptr)); 01018 } 01019 01020 /** 01021 * A version of the operator for move assignment which enables 01022 * pointer type conversion (assuming the type passed is implicitly 01023 * type convertible to the managed type, such as a derived type). 01024 * This method does not throw unless the destructor of a managed 01025 * object throws. 01026 * @param sh_ptr the shared pointer to be moved. 01027 * @return The SharedLockPtr object after the move operation. 01028 */ 01029 template <class U> SharedLockPtr& operator=(SharedLockPtr<U>&& sh_ptr) { 01030 return operator=(SharedLockPtr(std::move(sh_ptr))); 01031 } 01032 01033 /** 01034 * This method does not throw. 01035 * @return A pointer to the managed object (or NULL if none is 01036 * managed). 01037 */ 01038 T* get() const {return ref_items.obj_p;} 01039 01040 /** 01041 * This method does not throw. 01042 * @return A reference to the managed object. 01043 */ 01044 T& operator*() const {return *ref_items.obj_p;} 01045 01046 /** 01047 * This method does not throw. 01048 * @return A pointer to the managed object (or NULL if none is 01049 * managed). 01050 */ 01051 T* operator->() const {return ref_items.obj_p;} 01052 01053 /** 01054 * This method does not throw. 01055 * @return The number of SharedLockPtr objects referencing the 01056 * managed object (or 0 if none is managed by this SharedLockPtr). 01057 * @note The return value may not be valid if another thread has 01058 * changed the reference count before the value returned by this 01059 * method is acted on. It is provided as a utility, but may not be 01060 * meaningful, depending on the intended usage. 01061 */ 01062 unsigned int get_refcount() const { 01063 if (!ref_items.ref_count_p) return 0; 01064 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 01065 Thread::Mutex::Lock lock(*ref_items.mutex_p); 01066 return *ref_items.ref_count_p; 01067 #else 01068 return g_atomic_int_get(ref_items.ref_count_p); 01069 #endif 01070 } 01071 01072 /** 01073 * The destructor does not throw unless the destructor of a managed 01074 * object throws - that should never happen. 01075 */ 01076 ~SharedLockPtr() {unreference();} 01077 }; 01078 01079 #if defined(CGU_USE_SMART_PTR_COMPARISON) || defined(DOXYGEN_PARSING) 01080 01081 // we can use built-in operator == when comparing pointers referencing 01082 // different objects of the same type 01083 /** 01084 * @ingroup handles 01085 * 01086 * This comparison operator does not throw. It compares the addresses 01087 * of the managed objects. 01088 * 01089 * Since 2.0.0-rc2 01090 */ 01091 template <class T> 01092 bool operator==(const SharedPtr<T>& s1, const SharedPtr<T>& s2) { 01093 return (s1.get() == s2.get()); 01094 } 01095 01096 /** 01097 * @ingroup handles 01098 * 01099 * This comparison operator does not throw. It compares the addresses 01100 * of the managed objects. 01101 * 01102 * Since 2.0.0-rc2 01103 */ 01104 template <class T> 01105 bool operator!=(const SharedPtr<T>& s1, const SharedPtr<T>& s2) { 01106 return !(s1 == s2); 01107 } 01108 01109 // we must use std::less rather than the < built-in operator for 01110 // pointers to objects not within the same array or object: "For 01111 // templates greater, less, greater_equal, and less_equal, the 01112 // specializations for any pointer type yield a total order, even if 01113 // the built-in operators <, >, <=, >= do not." (para 20.3.3/8). 01114 /** 01115 * @ingroup handles 01116 * 01117 * This comparison operator does not throw. It compares the addresses 01118 * of the managed objects. 01119 * 01120 * Since 2.0.0-rc2 01121 */ 01122 template <class T> 01123 bool operator<(const SharedPtr<T>& s1, const SharedPtr<T>& s2) { 01124 return std::less<T*>()(s1.get(), s2.get()); 01125 } 01126 01127 /** 01128 * @ingroup handles 01129 * 01130 * This comparison operator does not throw. It compares the addresses 01131 * of the managed objects. 01132 * 01133 * Since 2.0.0-rc2 01134 */ 01135 template <class T> 01136 bool operator==(const SharedLockPtr<T>& s1, const SharedLockPtr<T>& s2) { 01137 return (s1.get() == s2.get()); 01138 } 01139 01140 /** 01141 * @ingroup handles 01142 * 01143 * This comparison operator does not throw. It compares the addresses 01144 * of the managed objects. 01145 * 01146 * Since 2.0.0-rc2 01147 */ 01148 template <class T> 01149 bool operator!=(const SharedLockPtr<T>& s1, const SharedLockPtr<T>& s2) { 01150 return !(s1 == s2); 01151 } 01152 01153 /** 01154 * @ingroup handles 01155 * 01156 * This comparison operator does not throw. It compares the addresses 01157 * of the managed objects. 01158 * 01159 * Since 2.0.0-rc2 01160 */ 01161 template <class T> 01162 bool operator<(const SharedLockPtr<T>& s1, const SharedLockPtr<T>& s2) { 01163 return std::less<T*>()(s1.get(), s2.get()); 01164 } 01165 01166 #endif // CGU_USE_SMART_PTR_COMPARISON 01167 01168 } // namespace Cgu 01169 01170 // doxygen produces long filenames that tar can't handle: 01171 // we have generic documentation for std::hash specialisations 01172 // in doxygen.main.in 01173 #if defined(CGU_USE_SMART_PTR_COMPARISON) && !defined(DOXYGEN_PARSING) 01174 /* These structs allow SharedPtr and SharedLockPtr objects to be keys 01175 in unordered associative containers */ 01176 namespace std { 01177 template <class T> 01178 struct hash<Cgu::SharedPtr<T>> { 01179 typedef std::size_t result_type; 01180 typedef Cgu::SharedPtr<T> argument_type; 01181 result_type operator()(const argument_type& s) const { 01182 // this is fine: std::hash structs do not normally contain data and 01183 // std::hash<T*> certainly won't, so we don't have overhead constructing 01184 // std::hash<T*> on the fly 01185 return std::hash<T*>()(s.get()); 01186 } 01187 }; 01188 template <class T> 01189 struct hash<Cgu::SharedLockPtr<T>> { 01190 typedef std::size_t result_type; 01191 typedef Cgu::SharedLockPtr<T> argument_type; 01192 result_type operator()(const argument_type& s) const { 01193 // this is fine: std::hash structs do not normally contain data and 01194 // std::hash<T*> certainly won't, so we don't have overhead constructing 01195 // std::hash<T*> on the fly 01196 return std::hash<T*>()(s.get()); 01197 } 01198 }; 01199 } // namespace std 01200 #endif // CGU_USE_SMART_PTR_COMPARISON 01201 01202 #endif