[419] | 1 | /*! |
---|
| 2 | \file |
---|
[529] | 3 | \brief BDM's own smart pointers. |
---|
[419] | 4 | \author Vaclav Barta. |
---|
| 5 | |
---|
| 6 | ----------------------------------- |
---|
| 7 | BDM++ - C++ library for Bayesian Decision Making under Uncertainty |
---|
| 8 | |
---|
| 9 | Using IT++ for numerical operations |
---|
| 10 | ----------------------------------- |
---|
| 11 | */ |
---|
| 12 | |
---|
| 13 | #ifndef shared_ptr_h |
---|
| 14 | #define shared_ptr_h |
---|
| 15 | |
---|
| 16 | #include <limits.h> |
---|
| 17 | #include <algorithm> |
---|
| 18 | #include <stdexcept> |
---|
| 19 | #include <string> |
---|
[565] | 20 | #include "bdmerror.h" |
---|
[419] | 21 | |
---|
| 22 | namespace bdm { |
---|
| 23 | |
---|
[555] | 24 | /*! \brief A naive implementation of roughly a subset of the std::tr1::shared_ptr spec |
---|
[529] | 25 | |
---|
| 26 | Really just roughly - it ignores memory |
---|
| 27 | exceptions, for example; also note I didn't read the spec. |
---|
| 28 | |
---|
[555] | 29 | The standard template would naturally be preferable, \b if it was |
---|
[529] | 30 | included in the standard libraries of all supported compilers - but |
---|
| 31 | as of 2009, that's still a problem... |
---|
| 32 | */ |
---|
[419] | 33 | template <typename T> |
---|
| 34 | class shared_ptr { |
---|
[477] | 35 | template<class U> friend class shared_ptr; |
---|
[461] | 36 | |
---|
[419] | 37 | private: |
---|
[477] | 38 | T *payload; |
---|
| 39 | unsigned *refCnt; |
---|
[419] | 40 | |
---|
| 41 | public: |
---|
[555] | 42 | /*! |
---|
| 43 | \brief Default constructor |
---|
| 44 | |
---|
| 45 | Creates an empty shared_ptr - one that doesn't point anywhere. |
---|
| 46 | */ |
---|
[477] | 47 | shared_ptr() : |
---|
| 48 | payload ( 0 ), |
---|
| 49 | refCnt ( 0 ) { |
---|
| 50 | } |
---|
[419] | 51 | |
---|
[737] | 52 | /*! |
---|
[529] | 53 | Constructs a shared_ptr that owns the pointer p (unless p |
---|
| 54 | is NULL, in which case this constructor creates an empty |
---|
| 55 | shared_ptr). When p isn't null, it must have been alllocated |
---|
| 56 | by new! |
---|
| 57 | */ |
---|
[477] | 58 | shared_ptr ( T *p ) : |
---|
| 59 | payload ( p ), |
---|
| 60 | refCnt ( p ? new unsigned ( 1 ) : 0 ) { |
---|
| 61 | } |
---|
[419] | 62 | |
---|
[555] | 63 | /*! |
---|
| 64 | \brief Copy constructor |
---|
| 65 | |
---|
| 66 | If other is empty, constructs an empty shared_ptr; otherwise, |
---|
| 67 | constructs a shared_ptr that shares ownership with other. |
---|
| 68 | */ |
---|
[477] | 69 | shared_ptr ( const shared_ptr<T> &other ) : |
---|
| 70 | payload ( other.payload ), |
---|
| 71 | refCnt ( other.refCnt ) { |
---|
| 72 | add_ref(); |
---|
| 73 | } |
---|
[419] | 74 | |
---|
[555] | 75 | /*! |
---|
| 76 | \brief Generalized copy |
---|
| 77 | |
---|
| 78 | Allows initialization of shared pointer of a base type from |
---|
| 79 | raw pointer to a derived type. |
---|
| 80 | |
---|
| 81 | If other is empty, constructs an empty shared_ptr; otherwise, |
---|
| 82 | constructs a shared_ptr that shares ownership with other. |
---|
| 83 | */ |
---|
[477] | 84 | template<typename U> |
---|
| 85 | shared_ptr ( const shared_ptr<U> &other ) : |
---|
| 86 | payload ( other.payload ), |
---|
| 87 | refCnt ( other.refCnt ) { |
---|
| 88 | add_ref(); |
---|
| 89 | } |
---|
[419] | 90 | |
---|
[555] | 91 | /*! |
---|
| 92 | Destructor. |
---|
| 93 | */ |
---|
[477] | 94 | ~shared_ptr() { |
---|
| 95 | del_ref(); |
---|
| 96 | } |
---|
[419] | 97 | |
---|
[555] | 98 | /*! |
---|
| 99 | \brief Assignment operator |
---|
| 100 | */ |
---|
[529] | 101 | shared_ptr<T> &operator= ( const shared_ptr<T> &other ) { |
---|
[477] | 102 | other.add_ref(); |
---|
| 103 | del_ref(); |
---|
[419] | 104 | |
---|
[477] | 105 | payload = other.payload; |
---|
| 106 | refCnt = other.refCnt; |
---|
[419] | 107 | |
---|
[477] | 108 | return *this; |
---|
| 109 | } |
---|
[419] | 110 | |
---|
[555] | 111 | /*! |
---|
| 112 | Returns the stored pointer (which remains owned by this |
---|
| 113 | instance). For empty instances, this method returns NULL. |
---|
| 114 | */ |
---|
[477] | 115 | T *get() { |
---|
| 116 | return payload; |
---|
| 117 | } |
---|
[419] | 118 | |
---|
[555] | 119 | /*! |
---|
| 120 | Dereferences the stored pointer (which remains owned by |
---|
| 121 | this instance). This method may only be called when the |
---|
| 122 | stored pointer isn't NULL. |
---|
| 123 | */ |
---|
[477] | 124 | T *operator->() { |
---|
[737] | 125 | if ( !payload ) { |
---|
| 126 | abort(); |
---|
| 127 | };// "dereferencing NULL" ); |
---|
[477] | 128 | return payload; |
---|
| 129 | } |
---|
[419] | 130 | |
---|
[477] | 131 | //! Returns a reference to the object pointed to by the stored |
---|
| 132 | //! pointer. This method may only be called when the stored pointer |
---|
| 133 | //! isn't NULL. |
---|
| 134 | T &operator*() { |
---|
[565] | 135 | bdm_assert_debug ( payload, "dereferencing NULL" ); |
---|
[477] | 136 | return *payload; |
---|
| 137 | } |
---|
[419] | 138 | |
---|
[555] | 139 | /*! |
---|
| 140 | Returns the stored pointer (which remains owned by this |
---|
| 141 | instance). For empty instances, this method returns NULL. |
---|
| 142 | */ |
---|
[477] | 143 | const T* get() const { |
---|
| 144 | return payload; |
---|
| 145 | } |
---|
[419] | 146 | |
---|
[477] | 147 | //! Returns the stored pointer (which remains owned by this |
---|
| 148 | //! instance). This method may only be called when the stored |
---|
| 149 | //! pointer isn't NULL. |
---|
| 150 | const T *operator->() const { |
---|
[565] | 151 | bdm_assert_debug ( payload, "dereferencing NULL" ); |
---|
[477] | 152 | return payload; |
---|
| 153 | } |
---|
[419] | 154 | |
---|
[477] | 155 | //! Returns a reference to the object pointed to by the stored |
---|
| 156 | //! pointer. This method may only be called when the stored pointer |
---|
| 157 | //! isn't NULL. |
---|
| 158 | const T &operator*() const { |
---|
[565] | 159 | bdm_assert_debug ( payload, "dereferencing NULL" ); |
---|
[477] | 160 | return *payload; |
---|
| 161 | } |
---|
[419] | 162 | |
---|
[555] | 163 | //! Returns use_count() == 1 |
---|
[477] | 164 | bool unique() const { |
---|
| 165 | return refCnt && ( *refCnt == 1 ); |
---|
| 166 | } |
---|
[419] | 167 | |
---|
[555] | 168 | /*! |
---|
| 169 | Returns the number of shared_ptr instances (including |
---|
| 170 | this instance) that share ownership with this instance. For |
---|
| 171 | empty instances, this method returns 0. |
---|
| 172 | */ |
---|
[477] | 173 | long use_count() const { |
---|
| 174 | return refCnt ? *refCnt : 0; |
---|
| 175 | } |
---|
[419] | 176 | |
---|
[555] | 177 | /*! |
---|
| 178 | \brief Boolean cast |
---|
| 179 | |
---|
| 180 | This operator returns true if and only if the instance isn't empty. |
---|
| 181 | */ |
---|
[477] | 182 | operator bool() const { |
---|
[554] | 183 | return !!payload; |
---|
[477] | 184 | } |
---|
[419] | 185 | |
---|
[555] | 186 | /*! |
---|
[570] | 187 | \brief const cast |
---|
| 188 | |
---|
| 189 | Shared pointer to T can be converted to shared pointer to |
---|
| 190 | const T, just like T * can be converted to T const *. |
---|
| 191 | */ |
---|
| 192 | template<typename U> |
---|
| 193 | operator shared_ptr<const U>() const { |
---|
[737] | 194 | shared_ptr<const U> cptr; |
---|
[570] | 195 | cptr.refCnt = refCnt; |
---|
| 196 | cptr.payload = payload; |
---|
| 197 | add_ref(); |
---|
| 198 | return cptr; |
---|
| 199 | } |
---|
| 200 | |
---|
| 201 | /*! |
---|
[555] | 202 | \brief Efficient swap for shared_ptr. |
---|
| 203 | */ |
---|
[477] | 204 | void swap ( shared_ptr &other ) { |
---|
| 205 | std::swap ( payload, other.payload ); |
---|
| 206 | std::swap ( refCnt, other.refCnt ); |
---|
| 207 | } |
---|
| 208 | |
---|
[419] | 209 | private: |
---|
[477] | 210 | void add_ref() const { |
---|
| 211 | if ( refCnt ) { |
---|
| 212 | if ( *refCnt == UINT_MAX ) { |
---|
| 213 | throw std::overflow_error ( |
---|
| 214 | std::string ( "Shared pointer has too many references." ) ); |
---|
| 215 | } |
---|
[419] | 216 | |
---|
[477] | 217 | ++*refCnt; |
---|
| 218 | } |
---|
[419] | 219 | } |
---|
| 220 | |
---|
[477] | 221 | void del_ref() { |
---|
| 222 | if ( refCnt ) { |
---|
| 223 | if ( ! ( --*refCnt ) ) { |
---|
| 224 | delete payload; |
---|
| 225 | delete refCnt; |
---|
| 226 | } |
---|
| 227 | } |
---|
[419] | 228 | } |
---|
| 229 | }; |
---|
| 230 | |
---|
[737] | 231 | //! Compare shared pointers |
---|
[419] | 232 | template<typename T, typename U> |
---|
[477] | 233 | bool operator== ( shared_ptr<T> const &a, shared_ptr<U> const &b ) { |
---|
| 234 | return a.get() == b.get(); |
---|
[419] | 235 | } |
---|
| 236 | |
---|
[737] | 237 | //! Compare shared pointers |
---|
[419] | 238 | template<typename T, typename U> |
---|
[477] | 239 | bool operator!= ( shared_ptr<T> const &a, shared_ptr<U> const &b ) { |
---|
| 240 | return a.get() != b.get(); |
---|
[419] | 241 | } |
---|
| 242 | |
---|
[737] | 243 | //! Compare shared pointers |
---|
[419] | 244 | template<typename T, typename U> |
---|
[477] | 245 | bool operator< ( shared_ptr<T> const &a, shared_ptr<U> const &b ) { |
---|
| 246 | return a.get() < b.get(); |
---|
[419] | 247 | } |
---|
| 248 | |
---|
[529] | 249 | /*! \brief A wrapper of shared_ptr which is never empty. |
---|
| 250 | |
---|
| 251 | T must have a default constructor. |
---|
| 252 | |
---|
| 253 | Note that shared_ptr's destructor isn't virtual - don't call delete |
---|
| 254 | on pointers to instances of this class. |
---|
| 255 | */ |
---|
| 256 | template <typename T> |
---|
[737] | 257 | class object_ptr : public shared_ptr<T> { |
---|
[529] | 258 | public: |
---|
| 259 | /*! |
---|
| 260 | \brief Default constructor |
---|
| 261 | |
---|
| 262 | Calls T's default constructor. |
---|
| 263 | */ |
---|
| 264 | object_ptr() : shared_ptr<T> ( new T() ) { } |
---|
| 265 | |
---|
| 266 | /*! |
---|
| 267 | \brief Upcast from shared_ptr<T> to object_ptr<T> |
---|
| 268 | |
---|
| 269 | \param b The shared pointer, which must not be empty. |
---|
| 270 | */ |
---|
| 271 | object_ptr ( const shared_ptr<T> &b ) : shared_ptr<T> ( b ) { |
---|
[565] | 272 | bdm_assert_debug ( this->get(), "object_ptr cannot be empty" ); |
---|
[529] | 273 | } |
---|
| 274 | |
---|
[737] | 275 | /*! |
---|
[529] | 276 | Constructs an object_ptr that owns the pointer p. p must |
---|
| 277 | have been alllocated by new! |
---|
| 278 | */ |
---|
| 279 | object_ptr ( T *p ) : shared_ptr<T> ( p ) { |
---|
[565] | 280 | bdm_assert_debug ( p, "object_ptr cannot be empty" ); |
---|
[529] | 281 | } |
---|
| 282 | |
---|
[555] | 283 | /*! |
---|
| 284 | \brief Assignment operator |
---|
| 285 | */ |
---|
[529] | 286 | object_ptr<T> &operator= ( const object_ptr<T> &other ) { |
---|
| 287 | shared_ptr<T>::operator= ( other ); |
---|
| 288 | return *this; |
---|
| 289 | } |
---|
| 290 | }; |
---|
| 291 | |
---|
| 292 | #define SHAREDPTR(class_name) typedef bdm::object_ptr< class_name > class_name##_ptr |
---|
| 293 | |
---|
| 294 | #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 |
---|
| 295 | |
---|
[419] | 296 | } |
---|
| 297 | |
---|
| 298 | #endif |
---|