Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * refptr.h - reference counting shared smartpointer 00004 * 00005 * Created: Sat Jan 24 12:29:41 2009 00006 * Copyright 2002 The gtkmm Development Team 00007 * 2005 The cairomm Development Team 00008 * 2009 Tim Niemueller [www.niemueller.de] 00009 * 00010 ****************************************************************************/ 00011 00012 /* This program is free software; you can redistribute it and/or modify 00013 * it under the terms of the GNU General Public License as published by 00014 * the Free Software Foundation; either version 2 of the License, or 00015 * (at your option) any later version. A runtime exception applies to 00016 * this software (see LICENSE.GPL_WRE file mentioned below for details). 00017 * 00018 * This program is distributed in the hope that it will be useful, 00019 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00021 * GNU Library General Public License for more details. 00022 * 00023 * Read the full text in the LICENSE.GPL_WRE file in the doc directory. 00024 */ 00025 00026 #ifndef __CORE_UTILS_REFPTR_H_ 00027 #define __CORE_UTILS_REFPTR_H_ 00028 00029 #include <core/threading/mutex.h> 00030 00031 namespace fawkes { 00032 00033 /** RefPtr<> is a reference-counting shared smartpointer. 00034 * 00035 * Reference counting means that a shared reference count is incremented each 00036 * time a RefPtr is copied, and decremented each time a RefPtr is destroyed, 00037 * for instance when it leaves its scope. When the reference count reaches 00038 * zero, the contained object is deleted 00039 * 00040 * Fawkes uses RefPtr so that you don't need to remember 00041 * to delete the object explicitly, or know when a method expects you to delete 00042 * the object that it returns. 00043 * 00044 * Note that RefPtr is thread-safe. 00045 * 00046 * @ingroup FCL 00047 */ 00048 template <class T_CppObject> 00049 class RefPtr 00050 { 00051 public: 00052 /** Default constructor 00053 * 00054 * Afterwards it will be null and use of -> will cause a segmentation fault. 00055 */ 00056 inline RefPtr(); 00057 00058 /// Destructor - decrements reference count. 00059 inline ~RefPtr(); 00060 00061 /** Constructor that takes ownership. 00062 * 00063 * This takes ownership of @a cpp_object, so it will be deleted when the 00064 * last RefPtr is deleted, for instance when it goes out of scope. 00065 * @param cpp_object C++ object to take ownership of 00066 */ 00067 explicit inline RefPtr(T_CppObject* cpp_object); 00068 00069 /** Copy constructor 00070 * This increments the shared reference count. 00071 * @param src refptr to copy 00072 */ 00073 inline RefPtr(const RefPtr<T_CppObject>& src); 00074 00075 /** Copy constructor (from different, but castable type). 00076 * Increments the reference count. 00077 * @param src refptr to copy 00078 */ 00079 template <class T_CastFrom> 00080 inline RefPtr(const RefPtr<T_CastFrom>& src); 00081 00082 /** Swap the contents of two RefPtr<>. 00083 * This method swaps the internal pointers to T_CppObject. This can be 00084 * done safely without involving a reference/unreference cycle and is 00085 * therefore highly efficient. 00086 * @param other other instance to swap with. 00087 */ 00088 inline void swap(RefPtr<T_CppObject>& other); 00089 00090 /** Copy from another RefPtr. 00091 * @param src refptr to copy from 00092 * @return reference to this instance 00093 */ 00094 inline RefPtr<T_CppObject>& operator=(const RefPtr<T_CppObject>& src); 00095 00096 /** Copy from different, but castable type). 00097 * Increments the reference count. 00098 * @param src refptr to copy from 00099 * @return reference to this instance 00100 */ 00101 template <class T_CastFrom> 00102 inline RefPtr<T_CppObject>& operator=(const RefPtr<T_CastFrom>& src); 00103 00104 /** Assign object and claim ownership. 00105 * @param ptr pointer to object, this refptr will claim ownership of the src! 00106 * @return reference to this instance 00107 */ 00108 inline RefPtr<T_CppObject>& operator=(T_CppObject *ptr); 00109 00110 00111 /** Tests whether the RefPtr<> point to the same underlying instance. 00112 * @param src refptr to compare to 00113 * @return true if both refptrs point to the same instance. 00114 */ 00115 inline bool operator==(const RefPtr<T_CppObject>& src) const; 00116 00117 /** Tests whether the RefPtr<> do not point to the same underlying instance. 00118 * @param src refptr to compare to 00119 * @return true if both refptrs do not point to the same instance. 00120 */ 00121 inline bool operator!=(const RefPtr<T_CppObject>& src) const; 00122 00123 /** Dereferencing. 00124 * Use the methods of the underlying instance like so: 00125 * <code>refptr->memberfun()</code>. 00126 * @return pointer to encapsulated object 00127 */ 00128 inline T_CppObject* operator->() const; 00129 00130 /** Get underlying pointer. 00131 * Use with care! 00132 * @return pointer to encapsulated object 00133 */ 00134 inline T_CppObject* operator*() const; 00135 00136 00137 /** Test whether the RefPtr<> points to any underlying instance. 00138 * 00139 * Mimics usage of ordinary pointers: 00140 * @code 00141 * if (ptr) 00142 * do_something(); 00143 * @endcode 00144 */ 00145 inline operator bool() const; 00146 00147 /// Set underlying instance to 0, decrementing reference count of existing instance appropriately. 00148 inline void clear(); 00149 00150 /** Reset pointer. 00151 * Set underlying instance to 0, decrementing reference count of 00152 * existing instance appropriately. 00153 */ 00154 inline void reset(); 00155 00156 00157 /** Dynamic cast to derived class. 00158 * 00159 * The RefPtr can't be cast with the usual notation so instead you can use 00160 * @code 00161 * ptr_derived = RefPtr<Derived>::cast_dynamic(ptr_base); 00162 * @endcode 00163 * @param src source refptr to cast 00164 * @return refptr to object casted to given type 00165 */ 00166 template <class T_CastFrom> 00167 static inline RefPtr<T_CppObject> cast_dynamic(const RefPtr<T_CastFrom>& src); 00168 00169 /** Static cast to derived class. 00170 * 00171 * Like the dynamic cast; the notation is 00172 * @code 00173 * ptr_derived = RefPtr<Derived>::cast_static(ptr_base); 00174 * @endcode 00175 * @param src source refptr to cast 00176 * @return refptr to object casted to given type 00177 */ 00178 template <class T_CastFrom> 00179 static inline RefPtr<T_CppObject> cast_static(const RefPtr<T_CastFrom>& src); 00180 00181 /** Cast to non-const. 00182 * 00183 * The RefPtr can't be cast with the usual notation so instead you can use 00184 * @code 00185 * ptr_unconst = RefPtr<UnConstType>::cast_const(ptr_const); 00186 * @endcode 00187 * @param src source refptr to cast 00188 * @return refptr to object casted to given type 00189 */ 00190 template <class T_CastFrom> 00191 static inline RefPtr<T_CppObject> cast_const(const RefPtr<T_CastFrom>& src); 00192 00193 /** For use only in the internal implementation of sharedptr. 00194 * @param cpp_object C++ object to wrap 00195 * @param refcount reference count 00196 * @param refmutex reference count mutex 00197 */ 00198 explicit inline RefPtr(T_CppObject *cpp_object, int *refcount, Mutex *refmutex); 00199 00200 /** For use only in the internal implementation of sharedptr. 00201 * Get reference count pointer. 00202 * Warning: This is for internal use only. Do not manually modify the 00203 * reference count with this pointer. 00204 * @return pointer to refcount integer 00205 */ 00206 inline int * refcount_ptr() const { return __ref_count; } 00207 00208 /** Get current reference count. 00209 * @return current number of owners referencing this RefPtr. 00210 */ 00211 inline int use_count() const { return *__ref_count; } 00212 00213 /** For use only in the internal implementation of sharedptr. 00214 * Get reference mutex. 00215 * @return pointer to refcount mutex 00216 */ 00217 inline Mutex * refmutex_ptr() const { return __ref_mutex; } 00218 00219 private: 00220 00221 T_CppObject *__cpp_object; 00222 mutable int *__ref_count; 00223 mutable Mutex *__ref_mutex; 00224 00225 }; 00226 00227 00228 // RefPtr<>::operator->() comes first here since it's used by other methods. 00229 // If it would come after them it wouldn't be inlined. 00230 00231 template <class T_CppObject> inline 00232 T_CppObject* RefPtr<T_CppObject>::operator->() const 00233 { 00234 return __cpp_object; 00235 } 00236 00237 00238 template <class T_CppObject> inline 00239 T_CppObject* RefPtr<T_CppObject>::operator*() const 00240 { 00241 return __cpp_object; 00242 } 00243 00244 template <class T_CppObject> inline 00245 RefPtr<T_CppObject>::RefPtr() 00246 : 00247 __cpp_object(0), 00248 __ref_count(0), 00249 __ref_mutex(0) 00250 {} 00251 00252 template <class T_CppObject> inline 00253 RefPtr<T_CppObject>::~RefPtr() 00254 { 00255 if(__ref_count && __ref_mutex) 00256 { 00257 __ref_mutex->lock(); 00258 00259 --(*__ref_count); 00260 00261 if(*__ref_count == 0) 00262 { 00263 if(__cpp_object) 00264 { 00265 delete __cpp_object; 00266 __cpp_object = 0; 00267 } 00268 00269 delete __ref_count; 00270 delete __ref_mutex; 00271 __ref_count = 0; 00272 __ref_mutex = 0; 00273 } else { 00274 __ref_mutex->unlock(); 00275 } 00276 } 00277 } 00278 00279 00280 template <class T_CppObject> inline 00281 RefPtr<T_CppObject>::RefPtr(T_CppObject* cpp_object) 00282 : 00283 __cpp_object(cpp_object), 00284 __ref_count(0), 00285 __ref_mutex(0) 00286 { 00287 if(cpp_object) 00288 { 00289 __ref_count = new int; 00290 __ref_mutex = new Mutex(); 00291 *__ref_count = 1; //This will be decremented in the destructor. 00292 } 00293 } 00294 00295 //Used by cast_*() implementations: 00296 template <class T_CppObject> inline 00297 RefPtr<T_CppObject>::RefPtr(T_CppObject* cpp_object, int* refcount, Mutex *refmutex) 00298 : 00299 __cpp_object(cpp_object), 00300 __ref_count(refcount), 00301 __ref_mutex(refmutex) 00302 { 00303 if(__cpp_object && __ref_count && __ref_mutex) { 00304 __ref_mutex->lock(); 00305 ++(*__ref_count); 00306 __ref_mutex->unlock(); 00307 } 00308 } 00309 00310 template <class T_CppObject> inline 00311 RefPtr<T_CppObject>::RefPtr(const RefPtr<T_CppObject>& src) 00312 : 00313 __cpp_object (src.__cpp_object), 00314 __ref_count(src.__ref_count), 00315 __ref_mutex(src.__ref_mutex) 00316 { 00317 if(__cpp_object && __ref_count && __ref_mutex) 00318 { 00319 __ref_mutex->lock(); 00320 ++(*__ref_count); 00321 __ref_mutex->unlock(); 00322 } 00323 } 00324 00325 // The templated ctor allows copy construction from any object that's 00326 // castable. Thus, it does downcasts: 00327 // base_ref = derived_ref 00328 template <class T_CppObject> 00329 template <class T_CastFrom> 00330 inline 00331 RefPtr<T_CppObject>::RefPtr(const RefPtr<T_CastFrom>& src) 00332 : 00333 // A different RefPtr<> will not allow us access to __cpp_object. We need 00334 // to add a get_underlying() for this, but that would encourage incorrect 00335 // use, so we use the less well-known operator->() accessor: 00336 __cpp_object (src.operator->()), 00337 __ref_count(src.refcount_ptr()), 00338 __ref_mutex(src.refmutex_ptr()) 00339 { 00340 if(__cpp_object && __ref_count && __ref_mutex) { 00341 __ref_mutex->lock(); 00342 ++(*__ref_count); 00343 __ref_mutex->unlock(); 00344 } 00345 } 00346 00347 template <class T_CppObject> inline 00348 void 00349 RefPtr<T_CppObject>::swap(RefPtr<T_CppObject>& other) 00350 { 00351 T_CppObject *const temp = __cpp_object; 00352 int *temp_count = __ref_count; 00353 Mutex *temp_mutex = __ref_mutex; 00354 00355 __cpp_object = other.__cpp_object; 00356 __ref_count = other.__ref_count; 00357 __ref_mutex = other.__ref_mutex; 00358 00359 other.__cpp_object = temp; 00360 other.__ref_count = temp_count; 00361 other.__ref_mutex = temp_mutex; 00362 } 00363 00364 template <class T_CppObject> inline 00365 RefPtr<T_CppObject>& 00366 RefPtr<T_CppObject>::operator=(const RefPtr<T_CppObject>& src) 00367 { 00368 // In case you haven't seen the swap() technique to implement copy 00369 // assignment before, here's what it does: 00370 // 00371 // 1) Create a temporary RefPtr<> instance via the copy ctor, thereby 00372 // increasing the reference count of the source object. 00373 // 00374 // 2) Swap the internal object pointers of *this and the temporary 00375 // RefPtr<>. After this step, *this already contains the new pointer, 00376 // and the old pointer is now managed by temp. 00377 // 00378 // 3) The destructor of temp is executed, thereby unreferencing the 00379 // old object pointer. 00380 // 00381 // This technique is described in Herb Sutter's "Exceptional C++", and 00382 // has a number of advantages over conventional approaches: 00383 // 00384 // - Code reuse by calling the copy ctor. 00385 // - Strong exception safety for free. 00386 // - Self assignment is handled implicitely. 00387 // - Simplicity. 00388 // - It just works and is hard to get wrong; i.e. you can use it without 00389 // even thinking about it to implement copy assignment whereever the 00390 // object data is managed indirectly via a pointer, which is very common. 00391 00392 RefPtr<T_CppObject> temp (src); 00393 this->swap(temp); 00394 return *this; 00395 } 00396 00397 template <class T_CppObject> inline 00398 RefPtr<T_CppObject>& 00399 RefPtr<T_CppObject>::operator=(T_CppObject *ptr) 00400 { 00401 RefPtr<T_CppObject> temp(ptr); 00402 this->swap(temp); 00403 return *this; 00404 } 00405 00406 00407 template <class T_CppObject> 00408 template <class T_CastFrom> 00409 inline 00410 RefPtr<T_CppObject>& 00411 RefPtr<T_CppObject>::operator=(const RefPtr<T_CastFrom>& src) 00412 { 00413 RefPtr<T_CppObject> temp (src); 00414 this->swap(temp); 00415 return *this; 00416 } 00417 00418 template <class T_CppObject> inline 00419 bool 00420 RefPtr<T_CppObject>::operator==(const RefPtr<T_CppObject>& src) const 00421 { 00422 return (__cpp_object == src.__cpp_object); 00423 } 00424 00425 template <class T_CppObject> inline 00426 bool 00427 RefPtr<T_CppObject>::operator!=(const RefPtr<T_CppObject>& src) const 00428 { 00429 return (__cpp_object != src.__cpp_object); 00430 } 00431 00432 template <class T_CppObject> inline 00433 RefPtr<T_CppObject>::operator bool() const 00434 { 00435 return (__cpp_object != 0); 00436 } 00437 00438 template <class T_CppObject> inline 00439 void RefPtr<T_CppObject>::clear() 00440 { 00441 RefPtr<T_CppObject> temp; // swap with an empty RefPtr<> to clear *this 00442 this->swap(temp); 00443 } 00444 00445 template <class T_CppObject> inline 00446 void RefPtr<T_CppObject>::reset() 00447 { 00448 RefPtr<T_CppObject> temp; // swap with an empty RefPtr<> to clear *this 00449 this->swap(temp); 00450 } 00451 00452 template <class T_CppObject> 00453 template <class T_CastFrom> 00454 inline 00455 RefPtr<T_CppObject> 00456 RefPtr<T_CppObject>::cast_dynamic(const RefPtr<T_CastFrom>& src) 00457 { 00458 T_CppObject *const cpp_object = dynamic_cast<T_CppObject*>(src.operator->()); 00459 00460 if(cpp_object) //Check whether dynamic_cast<> succeeded so we don't pass a null object with a used refcount: 00461 return RefPtr<T_CppObject>(cpp_object, src.refcount_ptr(), src.refmutex_ptr()); 00462 else 00463 return RefPtr<T_CppObject>(); 00464 } 00465 00466 template <class T_CppObject> 00467 template <class T_CastFrom> 00468 inline 00469 RefPtr<T_CppObject> 00470 RefPtr<T_CppObject>::cast_static(const RefPtr<T_CastFrom>& src) 00471 { 00472 T_CppObject *const cpp_object = static_cast<T_CppObject*>(src.operator->()); 00473 00474 return RefPtr<T_CppObject>(cpp_object, src.refcount_ptr(), src.refmutex_ptr()); 00475 } 00476 00477 template <class T_CppObject> 00478 template <class T_CastFrom> 00479 inline 00480 RefPtr<T_CppObject> 00481 RefPtr<T_CppObject>::cast_const(const RefPtr<T_CastFrom>& src) 00482 { 00483 T_CppObject *const cpp_object = const_cast<T_CppObject*>(src.operator->()); 00484 00485 return RefPtr<T_CppObject>(cpp_object, src.refcount_ptr(), src.refmutex_ptr()); 00486 } 00487 00488 00489 /** Swap refptr instances. 00490 * @param lrp "left" refptr 00491 * @param rrp "right" refptr 00492 * @relates fawkes::RefPtr 00493 */ 00494 template <class T_CppObject> inline 00495 void 00496 swap(RefPtr<T_CppObject>& lrp, RefPtr<T_CppObject>& rrp) 00497 { 00498 lrp.swap(rrp); 00499 } 00500 00501 } // end namespace fawkes 00502 00503 00504 #endif