00001 00013 #ifndef shared_ptr_h 00014 #define shared_ptr_h 00015 00016 #include <limits.h> 00017 #include <algorithm> 00018 #include <stdexcept> 00019 #include <string> 00020 #include "bdmerror.h" 00021 00022 namespace bdm { 00023 00033 template <typename T> 00034 class shared_ptr { 00035 template<class U> friend class shared_ptr; 00036 00037 private: 00038 T *payload; 00039 unsigned *refCnt; 00040 00041 public: 00047 shared_ptr() : 00048 payload ( 0 ), 00049 refCnt ( 0 ) { 00050 } 00051 00058 shared_ptr ( T *p ) : 00059 payload ( p ), 00060 refCnt ( p ? new unsigned ( 1 ) : 0 ) { 00061 } 00062 00069 shared_ptr ( const shared_ptr<T> &other ) : 00070 payload ( other.payload ), 00071 refCnt ( other.refCnt ) { 00072 add_ref(); 00073 } 00074 00084 template<typename U> 00085 shared_ptr ( const shared_ptr<U> &other ) : 00086 payload ( other.payload ), 00087 refCnt ( other.refCnt ) { 00088 add_ref(); 00089 } 00090 00094 ~shared_ptr() { 00095 del_ref(); 00096 } 00097 00101 shared_ptr<T> &operator= ( const shared_ptr<T> &other ) { 00102 other.add_ref(); 00103 del_ref(); 00104 00105 payload = other.payload; 00106 refCnt = other.refCnt; 00107 00108 return *this; 00109 } 00110 00115 T *get() { 00116 return payload; 00117 } 00118 00124 T *operator->() { 00125 bdm_assert_debug ( payload, "dereferencing NULL" ); 00126 return payload; 00127 } 00128 00132 T &operator*() { 00133 bdm_assert_debug ( payload, "dereferencing NULL" ); 00134 return *payload; 00135 } 00136 00141 const T* get() const { 00142 return payload; 00143 } 00144 00148 const T *operator->() const { 00149 bdm_assert_debug ( payload, "dereferencing NULL" ); 00150 return payload; 00151 } 00152 00156 const T &operator*() const { 00157 bdm_assert_debug ( payload, "dereferencing NULL" ); 00158 return *payload; 00159 } 00160 00162 bool unique() const { 00163 return refCnt && ( *refCnt == 1 ); 00164 } 00165 00171 long use_count() const { 00172 return refCnt ? *refCnt : 0; 00173 } 00174 00180 operator bool() const { 00181 return !!payload; 00182 } 00183 00190 template<typename U> 00191 operator shared_ptr<const U>() const { 00192 shared_ptr<const U> cptr; 00193 cptr.refCnt = refCnt; 00194 cptr.payload = payload; 00195 add_ref(); 00196 return cptr; 00197 } 00198 00202 void swap ( shared_ptr &other ) { 00203 std::swap ( payload, other.payload ); 00204 std::swap ( refCnt, other.refCnt ); 00205 } 00206 00207 private: 00208 void add_ref() const { 00209 if ( refCnt ) { 00210 if ( *refCnt == UINT_MAX ) { 00211 throw std::overflow_error ( 00212 std::string ( "Shared pointer has too many references." ) ); 00213 } 00214 00215 ++*refCnt; 00216 } 00217 } 00218 00219 void del_ref() { 00220 if ( refCnt ) { 00221 if ( ! ( --*refCnt ) ) { 00222 delete payload; 00223 delete refCnt; 00224 } 00225 } 00226 } 00227 }; 00228 00230 template<typename T, typename U> 00231 bool operator== ( shared_ptr<T> const &a, shared_ptr<U> const &b ) { 00232 return a.get() == b.get(); 00233 } 00234 00236 template<typename T, typename U> 00237 bool operator!= ( shared_ptr<T> const &a, shared_ptr<U> const &b ) { 00238 return a.get() != b.get(); 00239 } 00240 00242 template<typename T, typename U> 00243 bool operator< ( shared_ptr<T> const &a, shared_ptr<U> const &b ) { 00244 return a.get() < b.get(); 00245 } 00246 00254 template <typename T> 00255 class object_ptr : public shared_ptr<T> 00256 { 00257 public: 00263 object_ptr() : shared_ptr<T> ( new T() ) { } 00264 00270 object_ptr ( const shared_ptr<T> &b ) : shared_ptr<T> ( b ) { 00271 bdm_assert_debug ( this->get(), "object_ptr cannot be empty" ); 00272 } 00273 00278 object_ptr ( T *p ) : shared_ptr<T> ( p ) { 00279 bdm_assert_debug ( p, "object_ptr cannot be empty" ); 00280 } 00281 00285 object_ptr<T> &operator= ( const object_ptr<T> &other ) { 00286 shared_ptr<T>::operator= ( other ); 00287 return *this; 00288 } 00289 }; 00290 00291 #define SHAREDPTR(class_name) typedef bdm::object_ptr< class_name > class_name##_ptr 00292 00293 #define SHAREDPTR2(template_class_name, template_parameter_name) typedef bdm::object_ptr< template_class_name < template_parameter_name > > template_class_name##_##template_parameter_name##_ptr 00294 00295 } 00296 00297 #endif