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