c++-gtk-utils
|
00001 /* Copyright (C) 2004 to 2012 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 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 hand 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 by compiling 00160 * the library with the --with-glib-memory-slices-no-compat 00161 * configuration option. 00162 * 00163 * (ii) If glib memory slices are not used (which do not throw), 00164 * constructing a shared pointer for a new managed object (or calling 00165 * reset() for a new managed object) might throw if internal 00166 * allocation fails. Although by default the Cgu::SharedPtr 00167 * implementation will delete the new managed object in such a case, 00168 * it also provides an alternative constructor and reset() method 00169 * which instead enable the new object to be accessed via the thrown 00170 * exception object so that user code can decide what to do; 00171 * std::shared_ptr deletes the new object in every case. 00172 * 00173 * (iii) A user can explicitly state whether the shared pointer object 00174 * is to have atomic increment and decrement-and-test with respect to 00175 * the reference count so that the reference count is thread safe 00176 * ('no' in the case of Cgu::SharedPtr, and 'yes' in the case of 00177 * Cgu::SharedLockPtr). Using atomic functions is unnecessary if the 00178 * managed object concerned is only addressed in one thread (and might 00179 * cause unwanted cache flushing in certain circumstances). 00180 * std::shared_ptr will generally always use atomic functions with 00181 * respect to its reference count in a multi-threaded program. 00182 * 00183 * In favour of C++11's std::shared_ptr, it has an associated 00184 * std::make_shared() factory function which will construct both the 00185 * referenced object and the shared pointer's reference count within a 00186 * single memory block when the first shared pointer managing a 00187 * particular object is constructed. Cgu::SharedPtr and 00188 * Cgu::SharedLockPtr always allocate these separately, but this is 00189 * partly mitigated by the use of glib memory slices to allocate the 00190 * reference count where the --with-glib-memory-slices-no-compat 00191 * configuration option is chosen. 00192 * 00193 * In addition, std::shared_ptr has an associated std::weak_ptr class, 00194 * which Cgu::SharedPtr does not (there is a Cgu::GobjWeakHandle 00195 * class, but that is cognate with Cgu::GobjHandle and is only usable 00196 * with GObjects). 00197 */ 00198 00199 template <class T> class SharedPtr { 00200 00201 #ifndef DOXYGEN_PARSING 00202 struct RefItems { 00203 unsigned int* ref_count_p; 00204 T* obj_p; 00205 } ref_items; 00206 #endif 00207 00208 void unreference() { 00209 if (!ref_items.ref_count_p) return; 00210 --(*ref_items.ref_count_p); 00211 if (*ref_items.ref_count_p == 0) { 00212 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT 00213 g_slice_free(unsigned int, ref_items.ref_count_p); 00214 #else 00215 delete ref_items.ref_count_p; 00216 #endif 00217 delete ref_items.obj_p; 00218 } 00219 } 00220 00221 void reference() { 00222 if (!ref_items.ref_count_p) return; 00223 ++(*ref_items.ref_count_p); 00224 } 00225 00226 public: 00227 /** 00228 * Constructor taking an unmanaged object. 00229 * @param ptr The object which the SharedPtr is to manage (if any). 00230 * @exception std::bad_alloc This constructor will not throw if the 00231 * 'ptr' argument has a NULL value (the default), otherwise it might 00232 * throw std::bad_alloc if memory is exhausted and the system throws 00233 * in that case. If such an exception is thrown, this constructor is 00234 * exception safe (it does not leak resources), but as well as 00235 * cleaning itself up this constructor will also delete the managed 00236 * object passed to it to avoid a memory leak. If such automatic 00237 * deletion is not wanted in that case, use the version of this 00238 * constructor taking a Cgu::SharedPtrAllocFail::Leave tag argument. 00239 * @note std::bad_alloc will not be thrown if the library has been 00240 * installed using the --with-glib-memory-slices-no-compat 00241 * configuration option: instead glib will terminate the program if it 00242 * is unable to obtain memory from the operating system. 00243 */ 00244 explicit SharedPtr(T* ptr = 0) { 00245 00246 if ((ref_items.obj_p = ptr)) { // not NULL 00247 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT 00248 ref_items.ref_count_p = g_slice_new(unsigned int); 00249 *ref_items.ref_count_p = 1; 00250 #else 00251 try { 00252 ref_items.ref_count_p = new unsigned int(1); 00253 } 00254 catch (...) { 00255 delete ptr; // if allocating the int referenced by ref_items.ref_count_p 00256 // has failed then delete the object to be referenced to 00257 // avoid a memory leak 00258 throw; 00259 } 00260 #endif 00261 } 00262 else ref_items.ref_count_p = 0; 00263 } 00264 00265 /** 00266 * Constructor taking an unmanaged object. 00267 * @param ptr The object which the SharedPtr is to manage. 00268 * @param tag Passing the tag emumerator 00269 * Cgu::SharedPtrAllocFail::leave causes this constructor not to 00270 * delete the new managed object passed as the 'ptr' argument in the 00271 * event of internal allocation in this method failing because of 00272 * memory exhaustion (in that event, Cgu::SharedPtrError will be 00273 * thrown). 00274 * @exception Cgu::SharedPtrError This constructor might throw 00275 * Cgu::SharedPtrError if memory is exhausted and the system would 00276 * otherwise throw std::bad_alloc in that case. This constructor is 00277 * exception safe (it does not leak resources), and if such an 00278 * exception is thrown it will clean itself up, but it will not 00279 * attempt to delete the new managed object passed to it. Access to 00280 * the object passed to the 'ptr' argument can be obtained via the 00281 * thrown Cgu::SharedPtrError object. 00282 * @note 1. On systems with over-commit/lazy-commit combined with 00283 * virtual memory (swap), it is rarely useful to check for memory 00284 * exhaustion, so in those cases this version of the constructor will 00285 * not be useful. 00286 * @note 2. If the library has been installed using the 00287 * --with-glib-memory-slices-no-compat configuration option this 00288 * version of the constructor will also not be useful: instead glib 00289 * will terminate the program if it is unable to obtain memory from 00290 * the operating system. 00291 */ 00292 SharedPtr(T* ptr, Cgu::SharedPtrAllocFail::Leave tag) { 00293 00294 if ((ref_items.obj_p = ptr)) { // not NULL 00295 #ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT 00296 ref_items.ref_count_p = g_slice_new(unsigned int); 00297 *ref_items.ref_count_p = 1; 00298 #else 00299 try { 00300 ref_items.ref_count_p = new unsigned int(1); 00301 } 00302 catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly 00303 throw SharedPtrError<T>(ptr); 00304 } 00305 #endif 00306 } 00307 else ref_items.ref_count_p = 0; 00308 } 00309 00310 /** 00311 * Causes the SharedPtr to cease to manage its managed object (if 00312 * any), deleting it if this is the last SharedPtr object managing it. 00313 * If the argument passed is not NULL, the SharedPtr object will 00314 * manage the new object passed (which must not be managed by any 00315 * other SharedPtr object). This method is exception safe, but see 00316 * the comments below on std::bad_alloc. 00317 * @param ptr NULL (the default), or a new unmanaged object to manage. 00318 * @exception std::bad_alloc This method will not throw if the 'ptr' 00319 * argument has a NULL value (the default) and the destructor of a 00320 * managed object does not throw, otherwise it might throw 00321 * std::bad_alloc if memory is exhausted and the system throws in that 00322 * case. Note that if such an exception is thrown then this method 00323 * will do nothing (it is strongly exception safe and will continue to 00324 * manage the object it was managing prior to the call), except that 00325 * it will delete the new managed object passed to it to avoid a 00326 * memory leak. If such automatic deletion in the event of such an 00327 * exception is not wanted, use the reset() method taking a 00328 * Cgu::SharedPtrAllocFail::Leave tag type as its second argument. 00329 * @note std::bad_alloc will not be thrown if the library has been 00330 * installed using the --with-glib-memory-slices-no-compat 00331 * configuration option: instead glib will terminate the program if it 00332 * is unable to obtain memory from the operating system. 00333 */ 00334 void reset(T* ptr = 0) { 00335 SharedPtr tmp(ptr); 00336 std::swap(ref_items, tmp.ref_items); 00337 } 00338 00339 /** 00340 * Causes the SharedPtr to cease to manage its managed object (if 00341 * any), deleting it if this is the last SharedPtr object managing it. 00342 * The SharedPtr object will manage the new object passed (which must 00343 * not be managed by any other SharedPtr object). This method is 00344 * exception safe, but see the comments below on Cgu::SharedPtrError. 00345 * @param ptr A new unmanaged object to manage (if no new object is to 00346 * be managed, use the version of reset() taking a default value of 00347 * NULL). 00348 * @param tag Passing the tag emumerator 00349 * Cgu::SharedPtrAllocFail::leave causes this method not to delete the 00350 * new managed object passed as the 'ptr' argument in the event of 00351 * internal allocation in this method failing because of memory 00352 * exhaustion (in that event, Cgu::SharedPtrError will be thrown). 00353 * @exception Cgu::SharedPtrError This method might throw 00354 * Cgu::SharedPtrError if memory is exhausted and the system would 00355 * otherwise throw std::bad_alloc in that case. Note that if such an 00356 * exception is thrown then this method will do nothing (it is 00357 * strongly exception safe and will continue to manage the object it 00358 * was managing prior to the call), and it will not attempt to delete 00359 * the new managed object passed to it. Access to the object passed 00360 * to the 'ptr' argument can be obtained via the thrown 00361 * Cgu::SharedPtrError object. 00362 * @note 1. On systems with over-commit/lazy-commit combined with 00363 * virtual memory (swap), it is rarely useful to check for memory 00364 * exhaustion, so in those cases this version of the reset() method 00365 * will not be useful. 00366 * @note 2. If the library has been installed using the 00367 * --with-glib-memory-slices-no-compat configuration option this 00368 * version of the reset() method will also not be useful: instead glib 00369 * will terminate the program if it is unable to obtain memory from 00370 * the operating system. 00371 */ 00372 void reset(T* ptr, Cgu::SharedPtrAllocFail::Leave tag) { 00373 SharedPtr tmp(ptr, tag); 00374 std::swap(ref_items, tmp.ref_items); 00375 } 00376 00377 /** 00378 * This copy constructor does not throw. 00379 * @param sh_ptr The shared pointer to be copied. 00380 */ 00381 SharedPtr(const SharedPtr& sh_ptr) { 00382 ref_items = sh_ptr.ref_items; 00383 reference(); 00384 } 00385 00386 /** 00387 * The move constructor does not throw. It has move semantics. 00388 * @param sh_ptr The shared pointer to be moved. 00389 */ 00390 SharedPtr(SharedPtr&& sh_ptr) { 00391 ref_items = sh_ptr.ref_items; 00392 sh_ptr.ref_items.ref_count_p = 0; 00393 sh_ptr.ref_items.obj_p = 0; 00394 } 00395 00396 template <class U> friend class SharedPtr; 00397 00398 /** 00399 * A version of the copy constructor which enables pointer type 00400 * conversion (assuming the type passed is implicitly type 00401 * convertible to the managed type, such as a derived type). This 00402 * copy constructor does not throw. 00403 * @param sh_ptr The shared pointer to be copied. 00404 */ 00405 template <class U> SharedPtr(const SharedPtr<U>& sh_ptr) { 00406 // because we are allowing an implicit cast from derived to 00407 // base class referenced object, we need to assign from each 00408 // member of sh_ptr.ref_items separately 00409 ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p; 00410 ref_items.obj_p = sh_ptr.ref_items.obj_p; 00411 reference(); 00412 } 00413 00414 /** 00415 * A version of the move constructor which enables pointer type 00416 * conversion (assuming the type passed is implicitly type 00417 * convertible to the managed type, such as a derived type). This 00418 * move constructor does not throw. 00419 * @param sh_ptr The shared pointer to be moved. 00420 */ 00421 template <class U> SharedPtr(SharedPtr<U>&& sh_ptr) { 00422 // because we are allowing an implicit cast from derived to 00423 // base class referenced object, we need to assign from each 00424 // member of sh_ptr.ref_items separately 00425 ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p; 00426 ref_items.obj_p = sh_ptr.ref_items.obj_p; 00427 sh_ptr.ref_items.ref_count_p = 0; 00428 sh_ptr.ref_items.obj_p = 0; 00429 } 00430 00431 /** 00432 * This method (and so copy or move assignment) does not throw unless 00433 * the destructor of a managed object throws. 00434 * @param sh_ptr the assignor. 00435 * @return The SharedPtr object after assignment. 00436 */ 00437 // having a value type as the argument, rather than reference to const 00438 // and then initialising a tmp object, gives the compiler more scope 00439 // for optimisation, and also caters for r-values without a separate 00440 // overload 00441 SharedPtr& operator=(SharedPtr sh_ptr) { 00442 std::swap(ref_items, sh_ptr.ref_items); 00443 return *this; 00444 } 00445 00446 /** 00447 * A version of the assignment operator which enables pointer type 00448 * conversion (assuming the type passed is implicitly type 00449 * convertible to the managed type, such as a derived type). This 00450 * method does not throw unless the destructor of a managed object 00451 * throws. 00452 * @param sh_ptr the assignor. 00453 * @return The SharedPtr object after assignment. 00454 */ 00455 template <class U> SharedPtr& operator=(const SharedPtr<U>& sh_ptr) { 00456 return operator=(SharedPtr(sh_ptr)); 00457 } 00458 00459 /** 00460 * A version of the operator for move assignment which enables 00461 * pointer type conversion (assuming the type passed is implicitly 00462 * type convertible to the managed type, such as a derived type). 00463 * This method does not throw unless the destructor of a managed 00464 * object throws. 00465 * @param sh_ptr the shared pointer to be moved. 00466 * @return The SharedPtr object after the move operation. 00467 */ 00468 template <class U> SharedPtr& operator=(SharedPtr<U>&& sh_ptr) { 00469 return operator=(SharedPtr(std::move(sh_ptr))); 00470 } 00471 00472 /** 00473 * This method does not throw. 00474 * @return A pointer to the managed object (or NULL if none is 00475 * managed). 00476 */ 00477 T* get() const {return ref_items.obj_p;} 00478 00479 /** 00480 * This method does not throw. 00481 * @return A reference to the managed object. 00482 */ 00483 T& operator*() const {return *ref_items.obj_p;} 00484 00485 /** 00486 * This method does not throw. 00487 * @return A pointer to the managed object (or NULL if none is 00488 * managed). 00489 */ 00490 T* operator->() const {return ref_items.obj_p;} 00491 00492 /** 00493 * This method does not throw. 00494 * @return The number of SharedPtr objects referencing the managed 00495 * object (or 0 if none is managed by this SharedPtr). 00496 */ 00497 unsigned int get_refcount() const {return (ref_items.ref_count_p) ? *ref_items.ref_count_p : 0;} 00498 00499 /** 00500 * The destructor does not throw unless the destructor of a managed 00501 * object throws - that should never happen. 00502 */ 00503 ~SharedPtr() {unreference();} 00504 }; 00505 00506 /** 00507 * @class SharedLockPtr shared_ptr.h c++-gtk-utils/shared_ptr.h 00508 * @brief This is a smart pointer for managing the lifetime of objects 00509 * allocated on freestore, with a thread safe reference count. 00510 * @ingroup handles 00511 * @sa SharedPtr SharedPtrError 00512 * 00513 * Class SharedLockPtr is a version of the shared pointer class which 00514 * includes locking so that it can be accessed in multiple threads 00515 * (although the word Lock is in the title, by default it uses glib 00516 * atomic functions to access the reference count rather than a mutex, 00517 * so the overhead should be very small). Note that only the 00518 * reference count is protected, so this is thread safe in the sense 00519 * in which a raw pointer is thread safe. A shared pointer accessed 00520 * in one thread referencing a particular object is thread safe as 00521 * against another shared pointer accessing the same object in a 00522 * different thread. It is thus suitable for use in different Std C++ 00523 * containers which exist in different threads but which contain 00524 * shared objects by reference. But: 00525 * 00526 * 1. If the referenced object is to be modified in one thread and 00527 * read or modified in another thread an appropriate mutex for the 00528 * referenced object is required (unless that referenced object 00529 * does its own locking). 00530 * 00531 * 2. If the same instance of shared pointer is to be modified in one 00532 * thread (by assigning to the pointer so that it references a 00533 * different object, or by moving from it), and copied (assigned 00534 * from or used as the argument of a copy constructor), accessed, 00535 * destroyed or modified in another thread, a mutex for that 00536 * instance of shared pointer is required. 00537 * 00538 * 3. Objects referenced by shared pointers which are objects for 00539 * which POSIX provides no guarantees (in the main, those which 00540 * are not built-in types), such as strings and similar 00541 * containers, may not support concurrent reads in different 00542 * threads. That depends on the library implementation concerned. 00543 * If that is the case, a mutex for the referenced object will 00544 * also be required when reading any given instance of such an 00545 * object in more than one thread by dereferencing any shared 00546 * pointers referencing it (and indeed, when not using shared 00547 * pointers at all). 00548 * 00549 * As mentioned, by default glib atomic functions are used to provide 00550 * thread-safe manipulation of the reference count. However, a 00551 * library user can define the symbol CGU_SHARED_LOCK_PTR_USE_MUTEX 00552 * before shared_ptr.h is parsed so as to use mutexes instead, which 00553 * might be useful for some debugging purposes. 00554 * 00555 * @b Comparison @b with @b std::shared_ptr 00556 * 00557 * Most of the things that can be done by this class can be done by 00558 * using std::shared_ptr in C++11, but this class is retained in the 00559 * c++-gtk-utils library not only to retain compatibility with series 00560 * 1.2 of the library, but also to cater for some cases not met (or 00561 * not so easily met) by std::shared_ptr: 00562 * 00563 * (i) Glib memory slices provide an efficient small object allocator 00564 * (they are likely to be significantly more efficient than global 00565 * operator new()/new[](), which generally hand off to malloc(), and 00566 * whilst malloc() is good for large block allocations it is generally 00567 * poor as a small object allocator). Internal Cgu::SharedLockPtr 00568 * allocation using glib memory slices can be achieved by compiling 00569 * the library with the --with-glib-memory-slices-no-compat 00570 * configuration option. 00571 * 00572 * (ii) If glib memory slices are not used (which do not throw), 00573 * constructing a shared pointer for a new managed object (or calling 00574 * reset() for a new managed object) might throw if internal 00575 * allocation fails. Although by default the Cgu::SharedLockPtr 00576 * implementation will delete the new managed object in such a case, 00577 * it also provides an alternative constructor and reset() method 00578 * which instead enable the new object to be accessed via the thrown 00579 * exception object so that user code can decide what to do; 00580 * std::shared_ptr deletes the new object in every case. 00581 * 00582 * (iii) A user can explicitly state whether the shared pointer object 00583 * is to have atomic increment and decrement-and-test with respect to 00584 * the reference count so that the reference count is thread safe 00585 * ('no' in the case of Cgu::SharedPtr, and 'yes' in the case of 00586 * Cgu::SharedLockPtr). Using atomic functions is unnecessary if the 00587 * managed object concerned is only addressed in one thread (and might 00588 * cause unwanted cache flushing in certain circumstances). 00589 * std::shared_ptr will generally always use atomic functions with 00590 * respect to its reference count in a multi-threaded program. 00591 * 00592 * In favour of C++11's std::shared_ptr, it has an associated 00593 * std::make_shared() factory function which will construct both the 00594 * referenced object and the shared pointer's reference count within a 00595 * single memory block when the first shared pointer managing a 00596 * particular object is constructed. Cgu::SharedPtr and 00597 * Cgu::SharedLockPtr always allocate these separately, but this is 00598 * partly mitigated by the use of glib memory slices to allocate the 00599 * reference count where the --with-glib-memory-slices-no-compat 00600 * configuration option is chosen. 00601 * 00602 * In addition, std::shared_ptr has an associated std::weak_ptr class, 00603 * which Cgu::SharedLockPtr does not (there is a Cgu::GobjWeakHandle 00604 * class, but that is cognate with Cgu::GobjHandle and is only usable 00605 * with GObjects), and shared_ptr objects also have some atomic store, 00606 * load and exchange functions provided for them which enable 00607 * concurrent modifications of the same instance of shared_ptr in 00608 * different threads to have defined results. 00609 */ 00610 00611 template <class T> class SharedLockPtr { 00612 00613 #ifndef DOXYGEN_PARSING 00614 struct RefItems { 00615 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00616 Thread::Mutex* mutex_p; 00617 unsigned int* ref_count_p; 00618 #else 00619 gint* ref_count_p; 00620 #endif 00621 T* obj_p; 00622 } ref_items; 00623 #endif 00624 00625 // SharedLockPtr<T>::unreference() does not throw if the destructor of the 00626 // contained object does not throw, because Thread::Mutex::~Mutex(), 00627 // Thread::Mutex::lock() and Thread::Mutex::unlock() do not throw 00628 void unreference() { 00629 // we can (and should) check whether ref_items.ref_count_p is NULL without 00630 // a lock, because that member is specific to this SharedLockPtr object. 00631 // Only the integer pointed to by it is shared amongst SharedLockPtr 00632 // objects and requires locking 00633 if (!ref_items.ref_count_p) return; 00634 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00635 ref_items.mutex_p->lock(); 00636 --(*ref_items.ref_count_p); 00637 if (*ref_items.ref_count_p == 0) { 00638 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT 00639 g_slice_free(unsigned int, ref_items.ref_count_p); 00640 # else 00641 delete ref_items.ref_count_p; 00642 # endif 00643 ref_items.mutex_p->unlock(); 00644 delete ref_items.mutex_p; 00645 delete ref_items.obj_p; 00646 } 00647 else ref_items.mutex_p->unlock(); 00648 #else 00649 if (g_atomic_int_dec_and_test(ref_items.ref_count_p)) { 00650 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT 00651 g_slice_free(gint, ref_items.ref_count_p); 00652 # else 00653 delete ref_items.ref_count_p; 00654 # endif 00655 delete ref_items.obj_p; 00656 } 00657 #endif 00658 } 00659 00660 // SharedLockPtr<T>::reference() does not throw because 00661 // Thread::Mutex::Lock::Lock() and Thread::Mutex::Lock::~Lock() do not throw 00662 void reference() { 00663 // we can (and should) check whether ref_items.ref_count_p is NULL without 00664 // a lock, because that member is specific to this SharedLockPtr object. 00665 // Only the integer pointed to by it is shared amongst SharedLockPtr 00666 // objects and requires locking 00667 if (!ref_items.ref_count_p) return; 00668 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00669 Thread::Mutex::Lock lock(*ref_items.mutex_p); 00670 ++(*ref_items.ref_count_p); 00671 #else 00672 g_atomic_int_inc(ref_items.ref_count_p); 00673 #endif 00674 } 00675 00676 public: 00677 /** 00678 * Constructor taking an unmanaged object. 00679 * @param ptr The object which the SharedLockPtr is to manage (if 00680 * any). 00681 * @exception std::bad_alloc This constructor will not throw if the 00682 * 'ptr' argument has a NULL value (the default), otherwise it might 00683 * throw std::bad_alloc if memory is exhausted and the system throws 00684 * in that case. If such an exception is thrown, this constructor is 00685 * exception safe (it does not leak resources), but as well as 00686 * cleaning itself up this constructor will also delete the managed 00687 * object passed to it to avoid a memory leak. If such automatic 00688 * deletion is not wanted in that case, use the version of this 00689 * constructor taking a Cgu::SharedPtrAllocFail::Leave tag argument. 00690 * @note 1. std::bad_alloc will not be thrown if the library has been 00691 * installed using the --with-glib-memory-slices-no-compat 00692 * configuration option: instead glib will terminate the program if it 00693 * is unable to obtain memory from the operating system. 00694 * @note 2. By default, glib atomic functions are used to provide 00695 * thread-safe manipulation of the reference count. However, a 00696 * library user can define the symbol CGU_SHARED_LOCK_PTR_USE_MUTEX 00697 * before shared_ptr.h is parsed so as to use mutexes instead, which 00698 * might be useful for some debugging purposes. Were she to do so, 00699 * Cgu::Thread::MutexError might be thrown by this constructor if 00700 * initialization of the mutex fails, but it is usually not worth 00701 * checking for this. 00702 */ 00703 explicit SharedLockPtr(T* ptr = 0) { 00704 00705 if ((ref_items.obj_p = ptr)) { // not NULL 00706 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00707 try { 00708 ref_items.mutex_p = new Thread::Mutex; 00709 } 00710 catch (...) { 00711 delete ptr; // if allocating the object referenced by ref_items.mutex_p 00712 // has failed then delete the object to be referenced to 00713 // avoid a memory leak 00714 throw; 00715 } 00716 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT 00717 ref_items.ref_count_p = g_slice_new(unsigned int); 00718 *ref_items.ref_count_p = 1; 00719 # else 00720 try { 00721 ref_items.ref_count_p = new unsigned int(1); 00722 } 00723 catch (...) { 00724 delete ref_items.mutex_p; 00725 delete ptr; 00726 throw; 00727 } 00728 # endif 00729 #else 00730 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT 00731 ref_items.ref_count_p = g_slice_new(gint); 00732 *ref_items.ref_count_p = 1; 00733 # else 00734 try { 00735 ref_items.ref_count_p = new gint(1); 00736 } 00737 catch (...) { 00738 delete ptr; // if allocating the int referenced by ref_items.ref_count_p 00739 // has failed then delete the object to be referenced to 00740 // avoid a memory leak 00741 throw; 00742 } 00743 # endif 00744 #endif 00745 } 00746 else { 00747 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00748 ref_items.mutex_p = 0; // make sure the value is valid as we may assign it 00749 #endif 00750 ref_items.ref_count_p = 0; 00751 } 00752 } 00753 00754 /** 00755 * Constructor taking an unmanaged object. 00756 * @param ptr The object which the SharedLockPtr is to manage. 00757 * @param tag Passing the tag emumerator 00758 * Cgu::SharedPtrAllocFail::leave causes this constructor not to 00759 * delete the new managed object passed as the 'ptr' argument in the 00760 * event of internal allocation in this method failing because of 00761 * memory exhaustion (in that event, Cgu::SharedPtrError will be 00762 * thrown). 00763 * @exception Cgu::SharedPtrError This constructor might throw 00764 * Cgu::SharedPtrError if memory is exhausted and the system would 00765 * otherwise throw std::bad_alloc in that case. This constructor is 00766 * exception safe (it does not leak resources), and if such an 00767 * exception is thrown it will clean itself up, but it will not 00768 * attempt to delete the new managed object passed to it. Access to 00769 * the object passed to the 'ptr' argument can be obtained via the 00770 * thrown Cgu::SharedPtrError object. 00771 * @note 1. On systems with over-commit/lazy-commit combined with 00772 * virtual memory (swap), it is rarely useful to check for memory 00773 * exhaustion, so in those cases this version of the constructor will 00774 * not be useful. 00775 * @note 2. If the library has been installed using the 00776 * --with-glib-memory-slices-no-compat configuration option this 00777 * version of the constructor will also not be useful: instead glib 00778 * will terminate the program if it is unable to obtain memory from 00779 * the operating system. 00780 * @note 3. By default, glib atomic functions are used to provide 00781 * thread-safe manipulation of the reference count. However, a 00782 * library user can define the symbol CGU_SHARED_LOCK_PTR_USE_MUTEX 00783 * before shared_ptr.h is parsed so as to use mutexes instead, which 00784 * might be useful for some debugging purposes. Were she to do so, 00785 * Cgu::SharedPtrError might be thrown by this constructor if 00786 * initialization of the mutex fails (even if the 00787 * --with-glib-memory-slices-no-compat configuration option is 00788 * chosen), but it is usually not worth checking for such mutex 00789 * initialization failure. 00790 */ 00791 SharedLockPtr(T* ptr, Cgu::SharedPtrAllocFail::Leave tag) { 00792 00793 if ((ref_items.obj_p = ptr)) { // not NULL 00794 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00795 try { 00796 ref_items.mutex_p = new Thread::Mutex; 00797 } 00798 catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly 00799 throw SharedPtrError<T>(ptr); 00800 } 00801 catch (Thread::MutexError&) { // as we are not rethrowing, make NPTL friendly 00802 throw SharedPtrError<T>(ptr); 00803 } 00804 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT 00805 ref_items.ref_count_p = g_slice_new(unsigned int); 00806 *ref_items.ref_count_p = 1; 00807 # else 00808 try { 00809 ref_items.ref_count_p = new unsigned int(1); 00810 } 00811 catch (std::bad_alloc&) { 00812 delete ref_items.mutex_p; 00813 throw SharedPtrError<T>(ptr); 00814 } 00815 # endif 00816 #else 00817 # ifdef CGU_USE_GLIB_MEMORY_SLICES_NO_COMPAT 00818 ref_items.ref_count_p = g_slice_new(gint); 00819 *ref_items.ref_count_p = 1; 00820 # else 00821 try { 00822 ref_items.ref_count_p = new gint(1); 00823 } 00824 catch (std::bad_alloc&) { // as we are not rethrowing, make NPTL friendly 00825 throw SharedPtrError<T>(ptr); 00826 } 00827 # endif 00828 #endif 00829 } 00830 else { 00831 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00832 ref_items.mutex_p = 0; // make sure the value is valid as we may assign it 00833 #endif 00834 ref_items.ref_count_p = 0; 00835 } 00836 } 00837 00838 /** 00839 * Causes the SharedLockPtr to cease to manage its managed object (if 00840 * any), deleting it if this is the last SharedLockPtr object managing 00841 * it. If the argument passed is not NULL, the SharedLockPtr object 00842 * will manage the new object passed (which must not be managed by any 00843 * other SharedLockPtr object). This method is exception safe, but 00844 * see the comments below on std::bad_alloc. 00845 * @param ptr NULL (the default), or a new unmanaged object to manage. 00846 * @exception std::bad_alloc This method will not throw if the 'ptr' 00847 * argument has a NULL value (the default) and the destructor of a 00848 * managed object does not throw, otherwise it might throw 00849 * std::bad_alloc if memory is exhausted and the system throws in that 00850 * case. Note that if such an exception is thrown then this method 00851 * will do nothing (it is strongly exception safe and will continue to 00852 * manage the object it was managing prior to the call), except that 00853 * it will delete the new managed object passed to it to avoid a 00854 * memory leak. If such automatic deletion in the event of such an 00855 * exception is not wanted, use the reset() method taking a 00856 * Cgu::SharedPtrAllocFail::Leave tag type as its second argument. 00857 * @note 1. std::bad_alloc will not be thrown if the library has been 00858 * installed using the --with-glib-memory-slices-no-compat 00859 * configuration option: instead glib will terminate the program if it 00860 * is unable to obtain memory from the operating system. 00861 * @note 2. By default, glib atomic functions are used to provide 00862 * thread-safe manipulation of the reference count. However, a 00863 * library user can define the symbol CGU_SHARED_LOCK_PTR_USE_MUTEX 00864 * before shared_ptr.h is parsed so as to use mutexes instead, which 00865 * might be useful for some debugging purposes. Were she to do so, 00866 * Cgu::Thread::MutexError might be thrown by this method if 00867 * initialization of the mutex fails, but it is usually not worth 00868 * checking for this. 00869 * @note 3. A SharedLockPtr object protects its reference count but 00870 * not the managed object or its other internals. The reset() method 00871 * should not be called by one thread in respect of a particular 00872 * SharedLockPtr object while another thread may be operating on, 00873 * copying or dereferencing the same instance of SharedLockPtr. It is 00874 * thread-safe as against another instance of SharedLockPtr managing 00875 * the same object. 00876 */ 00877 void reset(T* ptr = 0) { 00878 SharedLockPtr tmp(ptr); 00879 std::swap(ref_items, tmp.ref_items); 00880 } 00881 00882 /** 00883 * Causes the SharedLockPtr to cease to manage its managed object (if 00884 * any), deleting it if this is the last SharedLockPtr object managing 00885 * it. The SharedLockPtr object will manage the new object passed 00886 * (which must not be managed by any other SharedLockPtr object). 00887 * This method is exception safe, but see the comments below on 00888 * Cgu::SharedPtrError. 00889 * @param ptr A new unmanaged object to manage (if no new object is to 00890 * be managed, use the version of reset() taking a default value of 00891 * NULL). 00892 * @param tag Passing the tag emumerator 00893 * Cgu::SharedPtrAllocFail::leave causes this method not to delete the 00894 * new managed object passed as the 'ptr' argument in the event of 00895 * internal allocation in this method failing because of memory 00896 * exhaustion (in that event, Cgu::SharedPtrError will be thrown). 00897 * @exception Cgu::SharedPtrError This method might throw 00898 * Cgu::SharedPtrError if memory is exhausted and the system would 00899 * otherwise throw std::bad_alloc in that case. Note that if such an 00900 * exception is thrown then this method will do nothing (it is 00901 * strongly exception safe and will continue to manage the object it 00902 * was managing prior to the call), and it will not attempt to delete 00903 * the new managed object passed to it. Access to the object passed 00904 * to the 'ptr' argument can be obtained via the thrown 00905 * Cgu::SharedPtrError object. 00906 * @note 1. A SharedLockPtr object protects its reference count but 00907 * not the managed object or its other internals. The reset() method 00908 * should not be called by one thread in respect of a particular 00909 * SharedLockPtr object while another thread may be operating on, 00910 * copying or dereferencing the same instance of SharedLockPtr. It is 00911 * thread-safe as against another instance of SharedLockPtr managing 00912 * the same object. 00913 * @note 2. On systems with over-commit/lazy-commit combined with 00914 * virtual memory (swap), it is rarely useful to check for memory 00915 * exhaustion, so in those cases this version of the reset() method 00916 * will not be useful. 00917 * @note 3. If the library has been installed using the 00918 * --with-glib-memory-slices-no-compat configuration option this 00919 * version of the reset() method will also not be useful: instead glib 00920 * will terminate the program if it is unable to obtain memory from 00921 * the operating system. 00922 * @note 4. By default, glib atomic functions are used to provide 00923 * thread-safe manipulation of the reference count. However, a 00924 * library user can define the symbol CGU_SHARED_LOCK_PTR_USE_MUTEX 00925 * before shared_ptr.h is parsed so as to use mutexes instead, which 00926 * might be useful for some debugging purposes. Were she to do so, 00927 * Cgu::SharedPtrError might be thrown by this method if 00928 * initialization of the mutex fails (even if the 00929 * --with-glib-memory-slices-no-compat configuration option is 00930 * chosen), but it is usually not worth checking for such mutex 00931 * initialization failure. 00932 */ 00933 void reset(T* ptr, Cgu::SharedPtrAllocFail::Leave tag) { 00934 SharedLockPtr tmp(ptr, tag); 00935 std::swap(ref_items, tmp.ref_items); 00936 } 00937 00938 /** 00939 * This copy constructor does not throw. 00940 * @param sh_ptr The shared pointer to be copied. 00941 */ 00942 SharedLockPtr(const SharedLockPtr& sh_ptr) { 00943 ref_items = sh_ptr.ref_items; 00944 reference(); 00945 } 00946 00947 /** 00948 * The move constructor does not throw. It has move semantics. 00949 * @param sh_ptr The shared pointer to be moved. 00950 */ 00951 SharedLockPtr(SharedLockPtr&& sh_ptr) { 00952 ref_items = sh_ptr.ref_items; 00953 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00954 sh_ptr.ref_items.mutex_p = 0; // make sure the value is valid as we may assign it 00955 #endif 00956 sh_ptr.ref_items.ref_count_p = 0; 00957 sh_ptr.ref_items.obj_p = 0; 00958 } 00959 00960 template <class U> friend class SharedLockPtr; 00961 00962 /** 00963 * A version of the copy constructor which enables pointer type 00964 * conversion (assuming the type passed is implicitly type 00965 * convertible to the managed type, such as a derived type). This 00966 * copy constructor does not throw. 00967 * @param sh_ptr The shared pointer to be copied. 00968 */ 00969 template <class U> SharedLockPtr(const SharedLockPtr<U>& sh_ptr) { 00970 // because we are allowing an implicit cast from derived to 00971 // base class referenced object, we need to assign from each 00972 // member of sh_ptr.ref_items separately 00973 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00974 ref_items.mutex_p = sh_ptr.ref_items.mutex_p; 00975 #endif 00976 ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p; 00977 ref_items.obj_p = sh_ptr.ref_items.obj_p; 00978 reference(); 00979 } 00980 00981 /** 00982 * A version of the move constructor which enables pointer type 00983 * conversion (assuming the type passed is implicitly type 00984 * convertible to the managed type, such as a derived type). This 00985 * move constructor does not throw. 00986 * @param sh_ptr The shared pointer to be moved. 00987 */ 00988 template <class U> SharedLockPtr(SharedLockPtr<U>&& sh_ptr) { 00989 // because we are allowing an implicit cast from derived to 00990 // base class referenced object, we need to assign from each 00991 // member of sh_ptr.ref_items separately 00992 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00993 ref_items.mutex_p = sh_ptr.ref_items.mutex_p; 00994 #endif 00995 ref_items.ref_count_p = sh_ptr.ref_items.ref_count_p; 00996 ref_items.obj_p = sh_ptr.ref_items.obj_p; 00997 00998 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 00999 sh_ptr.ref_items.mutex_p = 0; // make sure the value is valid as we may assign it 01000 #endif 01001 sh_ptr.ref_items.ref_count_p = 0; 01002 sh_ptr.ref_items.obj_p = 0; 01003 } 01004 01005 /** 01006 * This method (and so copy or move assignment) does not throw unless 01007 * the destructor of a managed object throws. 01008 * @param sh_ptr the assignor. 01009 * @return The SharedLockPtr object after assignment. 01010 */ 01011 // having a value type as the argument, rather than reference to const 01012 // and then initialising a tmp object, gives the compiler more scope 01013 // for optimisation, and also caters for r-values without a separate 01014 // overload 01015 SharedLockPtr& operator=(SharedLockPtr sh_ptr) { 01016 std::swap(ref_items, sh_ptr.ref_items); 01017 return *this; 01018 } 01019 01020 /** 01021 * A version of the assignment operator which enables pointer type 01022 * conversion (assuming the type passed is implicitly type 01023 * convertible to the managed type, such as a derived type). This 01024 * method does not throw unless the destructor of a managed object 01025 * throws. 01026 * @param sh_ptr the assignor. 01027 * @return The SharedLockPtr object after assignment. 01028 */ 01029 template <class U> SharedLockPtr& operator=(const SharedLockPtr<U>& sh_ptr) { 01030 return operator=(SharedLockPtr(sh_ptr)); 01031 } 01032 01033 /** 01034 * A version of the operator for move assignment which enables 01035 * pointer type conversion (assuming the type passed is implicitly 01036 * type convertible to the managed type, such as a derived type). 01037 * This method does not throw unless the destructor of a managed 01038 * object throws. 01039 * @param sh_ptr the shared pointer to be moved. 01040 * @return The SharedLockPtr object after the move operation. 01041 */ 01042 template <class U> SharedLockPtr& operator=(SharedLockPtr<U>&& sh_ptr) { 01043 return operator=(SharedLockPtr(std::move(sh_ptr))); 01044 } 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* get() const {return ref_items.obj_p;} 01052 01053 /** 01054 * This method does not throw. 01055 * @return A reference to the managed object. 01056 */ 01057 T& operator*() const {return *ref_items.obj_p;} 01058 01059 /** 01060 * This method does not throw. 01061 * @return A pointer to the managed object (or NULL if none is 01062 * managed). 01063 */ 01064 T* operator->() const {return ref_items.obj_p;} 01065 01066 /** 01067 * This method does not throw. 01068 * @return The number of SharedLockPtr objects referencing the 01069 * managed object (or 0 if none is managed by this SharedLockPtr). 01070 * @note The return value may not be valid if another thread has 01071 * changed the reference count before the value returned by this 01072 * method is acted on. It is provided as a utility, but may not be 01073 * meaningful, depending on the intended usage. 01074 */ 01075 unsigned int get_refcount() const { 01076 if (!ref_items.ref_count_p) return 0; 01077 #ifdef CGU_SHARED_LOCK_PTR_USE_MUTEX 01078 Thread::Mutex::Lock lock(*ref_items.mutex_p); 01079 return *ref_items.ref_count_p; 01080 #else 01081 return g_atomic_int_get(ref_items.ref_count_p); 01082 #endif 01083 } 01084 01085 /** 01086 * The destructor does not throw unless the destructor of a managed 01087 * object throws - that should never happen. 01088 */ 01089 ~SharedLockPtr() {unreference();} 01090 }; 01091 01092 #if defined(CGU_USE_SMART_PTR_COMPARISON) || defined(DOXYGEN_PARSING) 01093 01094 // we can use built-in operator == when comparing pointers referencing 01095 // different objects of the same type 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.get() == s2.get()); 01107 } 01108 01109 /** 01110 * @ingroup handles 01111 * 01112 * This comparison operator does not throw. It compares the addresses 01113 * of the managed objects. 01114 * 01115 * Since 2.0.0-rc2 01116 */ 01117 template <class T> 01118 bool operator!=(const SharedPtr<T>& s1, const SharedPtr<T>& s2) { 01119 return !(s1 == s2); 01120 } 01121 01122 // we must use std::less rather than the < built-in operator for 01123 // pointers to objects not within the same array or object: "For 01124 // templates greater, less, greater_equal, and less_equal, the 01125 // specializations for any pointer type yield a total order, even if 01126 // the built-in operators <, >, <=, >= do not." (para 20.3.3/8). 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 SharedPtr<T>& s1, const SharedPtr<T>& s2) { 01137 return std::less<T*>()(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.get() == s2.get()); 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 !(s1 == s2); 01164 } 01165 01166 /** 01167 * @ingroup handles 01168 * 01169 * This comparison operator does not throw. It compares the addresses 01170 * of the managed objects. 01171 * 01172 * Since 2.0.0-rc2 01173 */ 01174 template <class T> 01175 bool operator<(const SharedLockPtr<T>& s1, const SharedLockPtr<T>& s2) { 01176 return std::less<T*>()(s1.get(), s2.get()); 01177 } 01178 01179 #endif // CGU_USE_SMART_PTR_COMPARISON 01180 01181 } // namespace Cgu 01182 01183 // doxygen produces long filenames that tar can't handle: 01184 // we have generic documentation for std::hash specialisations 01185 // in doxygen.main.in 01186 #if defined(CGU_USE_SMART_PTR_COMPARISON) && !defined(DOXYGEN_PARSING) 01187 /* These structs allow SharedPtr and SharedLockPtr objects to be keys 01188 in unordered associative containers */ 01189 namespace std { 01190 template <class T> 01191 struct hash<Cgu::SharedPtr<T>> { 01192 typedef std::size_t result_type; 01193 typedef Cgu::SharedPtr<T> argument_type; 01194 result_type operator()(const argument_type& s) const { 01195 // this is fine: std::hash structs do not normally contain data and 01196 // std::hash<T*> certainly won't, so we don't have overhead constructing 01197 // std::hash<T*> on the fly 01198 return std::hash<T*>()(s.get()); 01199 } 01200 }; 01201 template <class T> 01202 struct hash<Cgu::SharedLockPtr<T>> { 01203 typedef std::size_t result_type; 01204 typedef Cgu::SharedLockPtr<T> argument_type; 01205 result_type operator()(const argument_type& s) const { 01206 // this is fine: std::hash structs do not normally contain data and 01207 // std::hash<T*> certainly won't, so we don't have overhead constructing 01208 // std::hash<T*> on the fly 01209 return std::hash<T*>()(s.get()); 01210 } 01211 }; 01212 } // namespace std 01213 #endif // CGU_USE_SMART_PTR_COMPARISON 01214 01215 #endif