shared_ptr.h

Go to the documentation of this file.
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
Generated on Sun May 8 08:42:12 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3