libmoost
/home/mhx/git/github/libmoost/include/moost/safe_shared_ptr.hpp
Go to the documentation of this file.
00001 /* vim:set ts=3 sw=3 sts=3 et: */
00028 #ifndef MOOST_SAFE_SHARED_PTR_HPP__
00029 #define MOOST_SAFE_SHARED_PTR_HPP__
00030 
00031 #include <boost/shared_ptr.hpp>
00032 #include <boost/thread/mutex.hpp>
00033 #include <boost/noncopyable.hpp>
00034 
00035 #include "compiler/attributes/deprecated.hpp"
00036 
00037 namespace moost {
00038 
00041 template <class T>
00042 class safe_shared_ptr
00043 {
00044 private:
00045 
00046   template<class Y> friend class safe_shared_ptr;
00047   template<class Y, class Z> friend bool operator==(safe_shared_ptr<Y> const &, safe_shared_ptr<Z> const &);
00048 
00049   boost::shared_ptr<T> p_;
00050   mutable boost::mutex mutex_;
00051 
00053   class Tester
00054   {
00055      void operator delete(void*);
00056   };
00057 
00058 public:
00059 
00060   typedef T element_type;
00061 
00062   safe_shared_ptr() // never throws
00063   {
00064   }
00065 
00066   template<class Y>
00067   explicit safe_shared_ptr(Y * p)
00068     : p_(p)
00069   {
00070   }
00071 
00072   template<class Y, class D>
00073   explicit safe_shared_ptr(Y * p, D d)
00074     : p_(p, d)
00075   {
00076   }
00077 
00078   template<class Y, class D, class A>
00079   explicit safe_shared_ptr(Y * p, D d, A a)
00080     : p_(p, d, a)
00081   {
00082   }
00083 
00084   safe_shared_ptr(safe_shared_ptr const & r)
00085     : p_(r.get_shared())
00086   {
00087   }
00088 
00089   template<class Y>
00090   safe_shared_ptr(safe_shared_ptr<Y> const & r) // never throws
00091     : p_(r.get_shared())
00092   {
00093   }
00094 
00095   template<class Y>
00096   safe_shared_ptr(boost::shared_ptr<Y> const & r) // never throws
00097     : p_(r)
00098   {
00099   }
00100 
00101   template<class Y>
00102   safe_shared_ptr(boost::shared_ptr<Y> const & r, T * p) // never throws
00103     : p_(r, p)
00104   {
00105   }
00106 
00107   template<class Y>
00108   explicit safe_shared_ptr(boost::weak_ptr<Y> const & r)
00109     : p_(r)
00110   {
00111   }
00112 
00113   template<class Y>
00114   explicit safe_shared_ptr(std::auto_ptr<Y> & r)
00115     : p_(r)
00116   {
00117   }
00118 
00119   safe_shared_ptr<T> & operator=(safe_shared_ptr<T> const & r) // never throws
00120   {
00121     if (this != &r)
00122     {
00123       boost::shared_ptr<T> tmp(r.get_shared());
00124       swap(tmp);
00125     }
00126     return *this;
00127   }
00128 
00129   safe_shared_ptr<T> & operator=(boost::shared_ptr<T> const & r) // never throws
00130   {
00131     boost::shared_ptr<T> tmp(r);
00132     swap(tmp);
00133     return *this;
00134   }
00135 
00136   void reset() // never throws
00137   {
00138     boost::shared_ptr<T> tmp;
00139     swap(tmp);
00140   }
00141 
00142   template<class Y>
00143   void reset(Y * p)
00144   {
00145     boost::shared_ptr<T> tmp(p);
00146     swap(tmp);
00147   }
00148 
00149   template<class Y, class D>
00150   void reset(Y * p, D d)
00151   {
00152     boost::shared_ptr<T> tmp(p, d);
00153     swap(tmp);
00154   }
00155 
00156   template<class Y, class D, class A>
00157   void reset(Y * p, D d, A a)
00158   {
00159     boost::shared_ptr<T> tmp(p, d, a);
00160     swap(tmp);
00161   }
00162 
00163   /*
00164    * The standard guarantees that you can safely call a method
00165    * or access a member on the temporary object returned by the
00166    * operator->(). As 12.2 [class.temporary] states, "temporary
00167    * objects are destroyed as the last step in evaluating the
00168    * full-expression that (lexically) contains the point where
00169    * they were created." This means that
00170    *
00171    *   a) the boost::shared_ptr<> will live for the duration of
00172    *      the method call (and possibly even longer if evaluation
00173    *      of the expression isn't finished when the method call
00174    *      returns) and
00175    *
00176    *   b) as a result, even if the safe_shared_ptr<> is either
00177    *      reset or destroyed, the temporary boost::shared_ptr<>
00178    *      will still keep the referenced object alive for the
00179    *      duration of expression evaluation.
00180    */
00181   boost::shared_ptr<T> operator->() const // never throws
00182   {
00183      return get_shared();
00184   }
00185 
00186   boost::shared_ptr<T> get_shared() const // never throws
00187   {
00188     boost::mutex::scoped_lock lock(mutex_);
00189     return p_;
00190   }
00191 
00192   bool unique() const // never throws
00193   {
00194     boost::mutex::scoped_lock lock(mutex_);
00195     return p_.unique();
00196   }
00197 
00198   long use_count() const // never throws
00199   {
00200     boost::mutex::scoped_lock lock(mutex_);
00201     return p_.use_count();
00202   }
00203 
00204   // operator! is redundant, but some compilers need it
00205   bool operator! () const // never throws
00206   {
00207     boost::mutex::scoped_lock lock(mutex_);
00208     return p_.operator !();
00209   }
00210 
00211   operator Tester*() const
00212   {
00213      {
00214        boost::mutex::scoped_lock lock(mutex_);
00215        if ( p_.get() == 0 )
00216          return 0;
00217      }
00218 
00219      static Tester test;
00220      return & test;
00221   }
00222 
00223   //operator bool() const // never throws
00224   //{
00225   //  boost::mutex::scoped_lock lock(mutex_);
00226   //  return p_.get() != 0;
00227   //}
00228 
00229   void swap(safe_shared_ptr<T> & b) // never throws
00230   {
00231     if (this != &b)
00232     {
00233       boost::mutex::scoped_lock lock1(&mutex_ < &b.mutex_ ? mutex_ : b.mutex_);
00234       boost::mutex::scoped_lock lock2(&mutex_ > &b.mutex_ ? mutex_ : b.mutex_);
00235       p_.swap(b.p_);
00236     }
00237   }
00238 
00239   void swap(boost::shared_ptr<T> & b)
00240   {
00241     boost::mutex::scoped_lock lock(mutex_);
00242     p_.swap(b);
00243   }
00244 
00245   // use safe_shared_ptr::scoped_lock if you want to deref multiple times but only lock once
00246   class scoped_lock : public boost::noncopyable
00247   {
00248   private:
00249 
00250     boost::mutex::scoped_lock lock_;
00251     boost::shared_ptr<T> & p_;
00252 
00253   public:
00254 
00255     scoped_lock(safe_shared_ptr<T> & p) : lock_(p.mutex_), p_(p.p_) {}
00256 
00257     void swap( boost::shared_ptr<T>& p ) { p_.swap(p); }
00258 
00259     T & operator*() const  { return p_.operator*(); } // never throws
00260     T * operator->() const { return p_.operator->(); } // never throws
00261     T * get() const        { return p_.get(); } // never throws
00262     bool unique() const    { return p_.unique(); } // never throws
00263     long use_count() const { return p_.use_count(); } // never throws
00264     operator bool() const  { return p_.operator bool(); } // never throws
00265   };
00266 
00267   class const_scoped_lock : public boost::noncopyable
00268   {
00269   private:
00270 
00271      boost::mutex::scoped_lock lock_;
00272      const boost::shared_ptr<T> & p_;
00273 
00274   public:
00275 
00276      const_scoped_lock(const safe_shared_ptr<T> & p) : lock_(p.mutex_), p_(p.p_) {}
00277 
00278      T & operator*() const  { return p_.operator*(); } // never throws
00279      T * operator->() const { return p_.operator->(); } // never throws
00280      T * get() const        { return p_.get(); } // never throws
00281      bool unique() const    { return p_.unique(); } // never throws
00282      long use_count() const { return p_.use_count(); } // never throws
00283      operator bool() const  { return p_.operator bool(); } // never throws
00284   };
00285 
00286 };
00287 
00288 template<class Y, class Z>
00289 inline bool operator==(safe_shared_ptr<Y> const & a, safe_shared_ptr<Z> const & b)
00290 {
00291   if (static_cast<const void *>(&a) == static_cast<const void *>(&b))
00292   {
00293     return true;
00294   }
00295   else
00296   {
00297     boost::mutex::scoped_lock lock1(&a.mutex_ < &b.mutex_ ? a.mutex_ : b.mutex_);
00298     boost::mutex::scoped_lock lock2(&a.mutex_ > &b.mutex_ ? a.mutex_ : b.mutex_);
00299     return a.p_ == b.p_;
00300   }
00301 }
00302 
00303 } // moost
00304 
00305 #endif // MOOST_SAFE_SHARED_PTR_HPP__