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                 if ( !payload) {abort();};
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