libmoost
|
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__