shared_ptr.h

Go to the documentation of this file.
00001 
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 10065 2007-04-12 05:54:56Z rjpeters $
00010 // $HeadURL: file:///lab/rjpeters/svnrepo/code/trunk/groovx/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 //
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 
00040 namespace rutz
00041 {
00042   namespace shared_ptr_aux
00043   {
00045     typedef void (ptr_check_function)(const void*);
00046 
00048 
00054     ptr_check_function* set_check_function(ptr_check_function* func);
00055 
00057     void check_ptr(const void* p);
00058   }
00059 
00060   template <class T> class shared_ptr;
00061 }
00062 
00064 
00079 template<class T>
00080 class rutz::shared_ptr
00081 {
00082 public:
00084 
00093   explicit inline shared_ptr(T* p =0);
00094 
00096   inline shared_ptr(const shared_ptr& r) throw();
00097 
00099 
00101   inline ~shared_ptr();
00102 
00104   inline shared_ptr& operator=(const shared_ptr& r);
00105 
00107 
00110   template<class TT>
00111   inline shared_ptr(const shared_ptr<TT>& r) throw();
00112 
00114 
00117   template<class TT>
00118   inline shared_ptr& operator=(const shared_ptr<TT>& r);
00119 
00121 
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 
00164   inline void reset(T* p=0);
00165 
00167   inline T& operator*() const throw() { return *px; }
00168 
00170   inline T* operator->() const throw() { return px; }
00171 
00173   inline T* get() const throw() { return px; }
00174 
00176   bool is_valid() const throw() { return px != 0; }
00177 
00179   bool is_invalid() const throw() { return px == 0; }
00180 
00182   inline int use_count() const throw() { return pn->atomic_get(); }
00183 
00185   inline bool unique() const throw() { return use_count() == 1; }
00186 
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 
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 
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 
00223   template <class T>
00224   inline shared_ptr<T> make_shared(T* t) { return shared_ptr<T>(t); }
00225 
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 
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 
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 
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 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00394 #endif // !GROOVX_RUTZ_SHARED_PTR_H_UTC20070412044942DEFINED

The software described here is Copyright (c) 1998-2005, Rob Peters.
This page was generated Wed Dec 3 06:49:41 2008 by Doxygen version 1.5.5.