00001 /** @file rutz/shared_ptr.h A thread-safe shared pointer class */ 00002 00003 /////////////////////////////////////////////////////////////////////// 00004 // 00005 // Copyright (c) 2006-2007 University of Southern California 00006 // Rob Peters <rjpeters at usc dot edu> 00007 // 00008 // created: Wed Aug 16 14:39:14 2006 00009 // commit: $Id: shared_ptr.h 8249 2007-04-12 06:03:40Z rjpeters $ 00010 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/rutz/shared_ptr.h $ 00011 // 00012 // -------------------------------------------------------------------- 00013 // 00014 // This file is part of GroovX. 00015 // [http://www.klab.caltech.edu/rjpeters/groovx/] 00016 // 00017 // GroovX is free software; you can redistribute it and/or modify it 00018 // under the terms of the GNU General Public License as published by 00019 // the Free Software Foundation; either version 2 of the License, or 00020 // (at your option) any later version. 00021 // 00022 // GroovX is distributed in the hope that it will be useful, but 00023 // WITHOUT ANY WARRANTY; without even the implied warranty of 00024 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00025 // General Public License for more details. 00026 // 00027 // You should have received a copy of the GNU General Public License 00028 // along with GroovX; if not, write to the Free Software Foundation, 00029 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 00030 // 00031 /////////////////////////////////////////////////////////////////////// 00032 00033 #ifndef GROOVX_RUTZ_SHARED_PTR_H_UTC20070412044942_DEFINED 00034 #define GROOVX_RUTZ_SHARED_PTR_H_UTC20070412044942_DEFINED 00035 00036 #include "rutz/atomic.h" 00037 #include "rutz/traits.h" 00038 00039 /// Auxiliary helper namespace used in implementing shared_ptr. 00040 namespace rutz 00041 { 00042 namespace shared_ptr_aux 00043 { 00044 /// Function type for checking whether a given pointer is allowed to be used in a shared_ptr. 00045 typedef void (ptr_check_function)(const void*); 00046 00047 /// Install a particular pointer-checking function. 00048 /** The ptr_check_function is expected to abort or throw an 00049 exception if it is passed a pointer that it considers invalid, 00050 otherwise it does nothing. set_check_function() returns a 00051 pointer to the previously-installed checking function, so that 00052 it is possible to save and later restore the previous 00053 value. */ 00054 ptr_check_function* set_check_function(ptr_check_function* func); 00055 00056 /// Call the current ptr_check_function, if it is non-null, otherwise do nothing. 00057 void check_ptr(const void* p); 00058 } 00059 00060 template <class T> class shared_ptr; 00061 } 00062 00063 //! A thread-safe smart pointer with reference counted copy semantics. 00064 /*! The object pointed to is deleted when the last shared_ptr pointing 00065 to it is destroyed or reset. Take note of the WARNING given in the 00066 documentation for the constructor that takes a raw pointer as its 00067 argument. 00068 00069 Borrowed and modified from boost.org smart_ptr.hpp 00070 Original copyright notice: 00071 00072 (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. Permission 00073 to copy, use, modify, sell and distribute this software is 00074 granted provided this copyright notice appears in all 00075 copies. This software is provided "as is" without express or 00076 implied warranty, and with no claim as to its suitability for any 00077 purpose. 00078 */ 00079 template<class T> 00080 class rutz::shared_ptr 00081 { 00082 public: 00083 //! Construct from a raw pointer. WARNING: do this only ONCE per pointer! 00084 /*! Bad Things (TM) will happen if this constructor is used multiple 00085 times to make multiple shared_ptr's from a single raw pointer; 00086 that's because each shared_ptr will start off thinking that it 00087 is the unique owner, and so they will each start their own ref 00088 count. If multiple shared_ptr's are needed for the same object 00089 (after all, that's the whole point of a shared ptr), only the 00090 first one should be constructed from the raw pointer, and 00091 subsequent ones should be constructed from the first using the 00092 copy constructor or assignment operator. */ 00093 explicit inline shared_ptr(T* p =0); 00094 00095 //! Copy another shared_ptr. The ref count is incremented by one. 00096 inline shared_ptr(const shared_ptr& r) throw(); 00097 00098 //! Destructor decrements the ref count by one. 00099 /*! If we were the last pointer to the pointee, then the pointee and 00100 the reference count are both delete'd. */ 00101 inline ~shared_ptr(); 00102 00103 //! Assign from another shared_ptr. The ref count is incremented by one. 00104 inline shared_ptr& operator=(const shared_ptr& r); 00105 00106 //! Copy construct from a shared_ptr of a different type. 00107 /*! The other type TT must be related to T by an appropriate 00108 inheritance relationship or by a change in 00109 const-qualification. */ 00110 template<class TT> 00111 inline shared_ptr(const shared_ptr<TT>& r) throw(); 00112 00113 //! Assign from a shared_ptr of a different type. 00114 /*! The other type TT must be related to T by an appropriate 00115 inheritance relationship or by a change in 00116 const-qualification. */ 00117 template<class TT> 00118 inline shared_ptr& operator=(const shared_ptr<TT>& r); 00119 00120 //! Assign from a shared_ptr of a different type, with dynamic casting. 00121 /*! This is the shared_ptr equivalent of doing a dynamic_cast 00122 between two raw pointers. Doing 'shared_ptr<T> ptr; 00123 ptr.dynCastFrom(other);' with 'other' a shared_ptr<TT> will 00124 internally do a dynamic_cast from TT* to T* and will assign the 00125 result to ptr. If the dynamic_cast succeeds, ptr and other will 00126 share the pointee as if they were two normal shared_ptr onto it 00127 (even though ptr and other are shared_ptr of different 00128 types). If the dynamic_cast fails then ptr will point to 00129 NULL. Typical usage of this is to recover an expected derived 00130 class from a base class: for example, <PRE> 00131 00132 // get our visual cortex from Brain. Brain provides a getVC() 00133 // function which returns a shared_ptr onto the VisualCortex 00134 // base class no matter which derivation of that we are actually 00135 // running right now: 00136 shared_ptr<VisualCortex> vcx = brain->getVC(); 00137 00138 // do something special if our VisualCortex actually happens to 00139 // be of type VisualCortexEyeMvt which is derived from 00140 // VisualCortex: 00141 shared_ptr<VisualCortexEyeMvt> vcem; 00142 vcem.dynCastFrom(vcx); 00143 00144 // vcem points to NULL unless the pointee of vcx could be 00145 // dynamic_cast'ed to vcem's type. 00146 if (vcem.isValid()) { 00147 // yes, indeed we are running a VisualCortexEyeMvt 00148 ... 00149 } 00150 </PRE> 00151 00152 Note: make sure you always use virtual destructors in your 00153 pointees, especially when you use dynCastFrom. Indeed, whichever 00154 shared_ptr is the last one to run out of scope will destroy the 00155 pointee. */ 00156 template <class TT> 00157 inline shared_ptr& dyn_cast_from(const shared_ptr<TT>& r); 00158 00159 template <class TT> 00160 inline shared_ptr& dynCastFrom(const shared_ptr<TT>& r) 00161 { return this->dyn_cast_from(r); } 00162 00163 //! Make the shared_ptr point to a different (optionally null) pointee. 00164 inline void reset(T* p=0); 00165 00166 //! Get a reference to the pointee. 00167 inline T& operator*() const throw() { return *px; } 00168 00169 //! Get the pointee for accessing its members. 00170 inline T* operator->() const throw() { return px; } 00171 00172 //! Get the pointee. 00173 inline T* get() const throw() { return px; } 00174 00175 //! Query whether the pointee is non-null. 00176 bool is_valid() const throw() { return px != 0; } 00177 00178 //! Query whether the pointee is non-null. 00179 bool is_invalid() const throw() { return px == 0; } 00180 00181 //! Query how many shared_ptr's are sharing the pointee. 00182 inline int use_count() const throw() { return pn->atomic_get(); } 00183 00184 //! Query whether the shared_ptr is the unique owner of its pointee. 00185 inline bool unique() const throw() { return use_count() == 1; } 00186 00187 //! Swap the pointees of two shared_ptr's. 00188 inline void swap(shared_ptr<T>& that) throw(); 00189 00190 private: 00191 T* px; // pointee 00192 rutz::atomic_int_t* pn; // reference count with atomic incr/decr operations 00193 00194 template<class TT> friend class shared_ptr; 00195 }; 00196 00197 00198 00199 // ###################################################################### 00200 // ###################################################################### 00201 // ##### INLINED FREE FUNCTIONS: 00202 // ###################################################################### 00203 // ###################################################################### 00204 00205 namespace rutz 00206 { 00207 00208 //! Test whether two shared_ptr's point to the same object. 00209 template<class T, class U> 00210 inline bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b) 00211 { 00212 return a.get() == b.get(); 00213 } 00214 00215 //! Test whether two shared_ptr's point to different objects. 00216 template<class T, class U> 00217 inline bool operator!=(const shared_ptr<T>& a, const shared_ptr<U>& b) 00218 { 00219 return a.get() != b.get(); 00220 } 00221 00222 //! A convenience function for making a shared_ptr out of a raw pointer. 00223 template <class T> 00224 inline shared_ptr<T> make_shared(T* t) { return shared_ptr<T>(t); } 00225 00226 //! Do a dynamic cast on a shared ptr 00227 template <class Dst, class Src> 00228 inline shared_ptr<Dst> dyn_cast(const shared_ptr<Src>& src) 00229 { 00230 shared_ptr<Dst> dst; 00231 dst.dyn_cast_from(src); 00232 return dst; 00233 } 00234 00235 //! Do a dynamic cast on a shared ptr 00236 template <class Dst, class Src> 00237 inline void dyn_cast_to_from(shared_ptr<Dst>& dst, const shared_ptr<Src>& src) 00238 { 00239 dst.dyn_cast_from(src); 00240 } 00241 00242 //! Synonym for dyn_cast 00243 template <class Dst, class Src> 00244 inline shared_ptr<Dst> dynCast(const shared_ptr<Src>& src) 00245 { return dyn_cast<Dst,Src>(src); } 00246 00247 //! Synonym for dyn_cast_to_from 00248 template <class Dst, class Src> 00249 inline void dynCastToFrom(shared_ptr<Dst>& dst, const shared_ptr<Src>& src) 00250 { dyn_cast_to_from<Dst,Src>(dst, src); } 00251 00252 } 00253 00254 // ###################################################################### 00255 // ###################################################################### 00256 // ##### INLINED MEMBER FUNCTIONS: 00257 // ###################################################################### 00258 // ###################################################################### 00259 00260 // ###################################################################### 00261 template <class T> inline 00262 rutz::shared_ptr<T>::shared_ptr(T* p) : 00263 px(p), pn(0) 00264 { 00265 #if defined(GVX_MEM_DEBUG) 00266 // Only call check_ptr() if GVX_MEM_DEBUG has been defined, because 00267 // this is a relatively expensive operation and can bog things down 00268 // if many shared_ptr objects are being created/destroyed in an 00269 // inner loop. 00270 00271 // We use full_object_cast() to get the address of the beginning of 00272 // the full object. That is slightly non-trivial, because, depending 00273 // on whether or not T is a polymorphic type, we might either have 00274 // to use a static_cast<void*> or a dynamic_cast<void*> to get the 00275 // full object address. That is all encapsulated by 00276 // rutz::full_object_cast(). 00277 rutz::shared_ptr_aux::check_ptr(rutz::full_object_cast(p)); 00278 #endif 00279 00280 // prevent leak if new throws: 00281 try { pn = new rutz::atomic_int_t; pn->atomic_set(1); } 00282 catch (...) { delete p; throw; } 00283 } 00284 00285 // ###################################################################### 00286 template <class T> inline 00287 rutz::shared_ptr<T>::shared_ptr(const shared_ptr<T>& r) throw() : 00288 px(r.px), pn(r.pn) 00289 { 00290 pn->atomic_incr(); 00291 } 00292 00293 // ###################################################################### 00294 template <class T> inline 00295 rutz::shared_ptr<T>::~shared_ptr() 00296 { 00297 if (pn->atomic_decr_test_zero()) 00298 { 00299 delete px; px = 0; 00300 delete pn; pn = 0; 00301 } 00302 } 00303 00304 // ###################################################################### 00305 template <class T> inline 00306 rutz::shared_ptr<T>& 00307 rutz::shared_ptr<T>::operator=(const rutz::shared_ptr<T>& r) 00308 { 00309 shared_ptr(r).swap(*this); 00310 return *this; 00311 } 00312 00313 // ###################################################################### 00314 template <class T> 00315 template<class TT> inline 00316 rutz::shared_ptr<T>::shared_ptr(const rutz::shared_ptr<TT>& r) throw() : 00317 px(r.px), pn(r.pn) 00318 { 00319 pn->atomic_incr(); 00320 } 00321 00322 // ###################################################################### 00323 template <class T> 00324 template<class TT> inline 00325 rutz::shared_ptr<T>& 00326 rutz::shared_ptr<T>::operator=(const rutz::shared_ptr<TT>& r) 00327 { 00328 shared_ptr(r).swap(*this); 00329 return *this; 00330 } 00331 00332 // ###################################################################### 00333 template <class T> 00334 template<class TT> inline 00335 rutz::shared_ptr<T>& 00336 rutz::shared_ptr<T>::dyn_cast_from(const rutz::shared_ptr<TT>& r) 00337 { 00338 // if we are already initialized to something (and we always are), 00339 // simulate a destroy: 00340 if (pn->atomic_decr_test_zero()) 00341 { 00342 delete px; px = 0; 00343 delete pn; pn = 0; 00344 } 00345 00346 // first do the dynamic_cast so we can test whether it succeeded: 00347 T* const new_px = dynamic_cast<T*>(r.px); 00348 00349 if (new_px == 0 && r.px != 0) 00350 { 00351 // the cast failed, so we set up a new ref count (NOTE: we DON'T 00352 // want to share the ref count in this case, because the 00353 // original shared_ptr and this shared_ptr will be pointing to 00354 // DIFFERENT objects -- the original has a valid pointer but we 00355 // have a null pointer): 00356 pn = new rutz::atomic_int_t; pn->atomic_set(1); 00357 } 00358 else 00359 { 00360 // share the ref count without increasing it: 00361 pn = r.pn; 00362 00363 // increase it to account for our existence: 00364 pn->atomic_incr(); 00365 00366 // share ownership of the original pointee: 00367 px = new_px; 00368 } 00369 return *this; 00370 } 00371 00372 // ###################################################################### 00373 template <class T> inline 00374 void rutz::shared_ptr<T>::reset(T* p) 00375 { 00376 shared_ptr(p).swap(*this); 00377 } 00378 00379 // ###################################################################### 00380 template <class T> inline 00381 void rutz::shared_ptr<T>::swap(shared_ptr<T>& that) throw() 00382 { 00383 T* that_px = that.px; that.px = this->px; this->px = that_px; 00384 rutz::atomic_int_t* that_pn = that.pn; that.pn = this->pn; this->pn = that_pn; 00385 } 00386 00387 // ###################################################################### 00388 /* So things look consistent in everyone's emacs... */ 00389 /* Local Variables: */ 00390 /* indent-tabs-mode: nil */ 00391 /* End: */ 00392 00393 static const char __attribute__((used)) vcid_groovx_rutz_shared_ptr_h_utc20070412044942[] = "$Id: shared_ptr.h 8249 2007-04-12 06:03:40Z rjpeters $ $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/rutz/shared_ptr.h $"; 00394 #endif // !GROOVX_RUTZ_SHARED_PTR_H_UTC20070412044942DEFINED