[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> |
---|
[420] | 20 | #include "itpp_ext.h" |
---|
[419] | 21 | |
---|
| 22 | namespace bdm { |
---|
| 23 | |
---|
[529] | 24 | /*! \brief A naive implementation of roughly a subset of the std::tr1:shared_ptr spec |
---|
| 25 | |
---|
| 26 | Really just roughly - it ignores memory |
---|
| 27 | exceptions, for example; also note I didn't read the spec. |
---|
| 28 | |
---|
| 29 | The standard template would naturally be preferable, _if_ it was |
---|
| 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: |
---|
[477] | 42 | //! Creates an empty shared_ptr - one that doesn't point anywhere. |
---|
| 43 | shared_ptr() : |
---|
| 44 | payload ( 0 ), |
---|
| 45 | refCnt ( 0 ) { |
---|
| 46 | } |
---|
[419] | 47 | |
---|
[529] | 48 | /*! |
---|
| 49 | Constructs a shared_ptr that owns the pointer p (unless p |
---|
| 50 | is NULL, in which case this constructor creates an empty |
---|
| 51 | shared_ptr). When p isn't null, it must have been alllocated |
---|
| 52 | by new! |
---|
| 53 | */ |
---|
[477] | 54 | shared_ptr ( T *p ) : |
---|
| 55 | payload ( p ), |
---|
| 56 | refCnt ( p ? new unsigned ( 1 ) : 0 ) { |
---|
| 57 | } |
---|
[419] | 58 | |
---|
[477] | 59 | //! If other is empty, constructs an empty shared_ptr; otherwise, |
---|
| 60 | //! constructs a shared_ptr that shares ownership with other. |
---|
| 61 | shared_ptr ( const shared_ptr<T> &other ) : |
---|
| 62 | payload ( other.payload ), |
---|
| 63 | refCnt ( other.refCnt ) { |
---|
| 64 | add_ref(); |
---|
| 65 | } |
---|
[419] | 66 | |
---|
[477] | 67 | //! If other is empty, constructs an empty shared_ptr; otherwise, |
---|
| 68 | //! constructs a shared_ptr that shares ownership with other. |
---|
| 69 | template<typename U> |
---|
| 70 | shared_ptr ( const shared_ptr<U> &other ) : |
---|
| 71 | payload ( other.payload ), |
---|
| 72 | refCnt ( other.refCnt ) { |
---|
| 73 | add_ref(); |
---|
| 74 | } |
---|
[419] | 75 | |
---|
[477] | 76 | ~shared_ptr() { |
---|
| 77 | del_ref(); |
---|
| 78 | } |
---|
[419] | 79 | |
---|
[529] | 80 | shared_ptr<T> &operator= ( const shared_ptr<T> &other ) { |
---|
[477] | 81 | other.add_ref(); |
---|
| 82 | del_ref(); |
---|
[419] | 83 | |
---|
[477] | 84 | payload = other.payload; |
---|
| 85 | refCnt = other.refCnt; |
---|
[419] | 86 | |
---|
[477] | 87 | return *this; |
---|
| 88 | } |
---|
[419] | 89 | |
---|
[477] | 90 | //! Returns the stored pointer (which remains owned by this |
---|
| 91 | //! instance). |
---|
| 92 | T *get() { |
---|
| 93 | return payload; |
---|
| 94 | } |
---|
[419] | 95 | |
---|
[477] | 96 | //! Returns the stored pointer (which remains owned by this |
---|
| 97 | //! instance). This method may only be called when the stored |
---|
| 98 | //! pointer isn't NULL. |
---|
| 99 | T *operator->() { |
---|
| 100 | it_assert_debug ( payload, "dereferencing NULL" ); |
---|
| 101 | return payload; |
---|
| 102 | } |
---|
[419] | 103 | |
---|
[477] | 104 | //! Returns a reference to the object pointed to by the stored |
---|
| 105 | //! pointer. This method may only be called when the stored pointer |
---|
| 106 | //! isn't NULL. |
---|
| 107 | T &operator*() { |
---|
| 108 | it_assert_debug ( payload, "dereferencing NULL" ); |
---|
| 109 | return *payload; |
---|
| 110 | } |
---|
[419] | 111 | |
---|
[477] | 112 | //! Returns the stored pointer (which remains owned by this |
---|
| 113 | //! instance). |
---|
| 114 | const T* get() const { |
---|
| 115 | return payload; |
---|
| 116 | } |
---|
[419] | 117 | |
---|
[477] | 118 | //! Returns the stored pointer (which remains owned by this |
---|
| 119 | //! instance). This method may only be called when the stored |
---|
| 120 | //! pointer isn't NULL. |
---|
| 121 | const T *operator->() const { |
---|
| 122 | it_assert_debug ( payload, "dereferencing NULL" ); |
---|
| 123 | return payload; |
---|
| 124 | } |
---|
[419] | 125 | |
---|
[477] | 126 | //! Returns a reference to the object pointed to by the stored |
---|
| 127 | //! pointer. This method may only be called when the stored pointer |
---|
| 128 | //! isn't NULL. |
---|
| 129 | const T &operator*() const { |
---|
| 130 | it_assert_debug ( payload, "dereferencing NULL" ); |
---|
| 131 | return *payload; |
---|
| 132 | } |
---|
[419] | 133 | |
---|
[477] | 134 | bool unique() const { |
---|
| 135 | return refCnt && ( *refCnt == 1 ); |
---|
| 136 | } |
---|
[419] | 137 | |
---|
[477] | 138 | long use_count() const { |
---|
| 139 | return refCnt ? *refCnt : 0; |
---|
| 140 | } |
---|
[419] | 141 | |
---|
[477] | 142 | operator bool() const { |
---|
| 143 | return payload; |
---|
| 144 | } |
---|
[419] | 145 | |
---|
[477] | 146 | void swap ( shared_ptr &other ) { |
---|
| 147 | std::swap ( payload, other.payload ); |
---|
| 148 | std::swap ( refCnt, other.refCnt ); |
---|
| 149 | } |
---|
| 150 | |
---|
[419] | 151 | private: |
---|
[477] | 152 | void add_ref() const { |
---|
| 153 | if ( refCnt ) { |
---|
| 154 | if ( *refCnt == UINT_MAX ) { |
---|
| 155 | throw std::overflow_error ( |
---|
| 156 | std::string ( "Shared pointer has too many references." ) ); |
---|
| 157 | } |
---|
[419] | 158 | |
---|
[477] | 159 | ++*refCnt; |
---|
| 160 | } |
---|
[419] | 161 | } |
---|
| 162 | |
---|
[477] | 163 | void del_ref() { |
---|
| 164 | if ( refCnt ) { |
---|
| 165 | if ( ! ( --*refCnt ) ) { |
---|
| 166 | delete payload; |
---|
| 167 | delete refCnt; |
---|
| 168 | } |
---|
| 169 | } |
---|
[419] | 170 | } |
---|
| 171 | }; |
---|
| 172 | |
---|
[536] | 173 | //! Compare shared pointers |
---|
[419] | 174 | template<typename T, typename U> |
---|
[477] | 175 | bool operator== ( shared_ptr<T> const &a, shared_ptr<U> const &b ) { |
---|
| 176 | return a.get() == b.get(); |
---|
[419] | 177 | } |
---|
| 178 | |
---|
[536] | 179 | //! Compare shared pointers |
---|
[419] | 180 | template<typename T, typename U> |
---|
[477] | 181 | bool operator!= ( shared_ptr<T> const &a, shared_ptr<U> const &b ) { |
---|
| 182 | return a.get() != b.get(); |
---|
[419] | 183 | } |
---|
| 184 | |
---|
[536] | 185 | //! Compare shared pointers |
---|
[419] | 186 | template<typename T, typename U> |
---|
[477] | 187 | bool operator< ( shared_ptr<T> const &a, shared_ptr<U> const &b ) { |
---|
| 188 | return a.get() < b.get(); |
---|
[419] | 189 | } |
---|
| 190 | |
---|
[529] | 191 | /*! \brief A wrapper of shared_ptr which is never empty. |
---|
| 192 | |
---|
| 193 | T must have a default constructor. |
---|
| 194 | |
---|
| 195 | Note that shared_ptr's destructor isn't virtual - don't call delete |
---|
| 196 | on pointers to instances of this class. |
---|
| 197 | */ |
---|
| 198 | template <typename T> |
---|
| 199 | class object_ptr : public shared_ptr<T> |
---|
| 200 | { |
---|
| 201 | public: |
---|
| 202 | /*! |
---|
| 203 | \brief Default constructor |
---|
| 204 | |
---|
| 205 | Calls T's default constructor. |
---|
| 206 | */ |
---|
| 207 | object_ptr() : shared_ptr<T> ( new T() ) { } |
---|
| 208 | |
---|
| 209 | /*! |
---|
| 210 | \brief Upcast from shared_ptr<T> to object_ptr<T> |
---|
| 211 | |
---|
| 212 | \param b The shared pointer, which must not be empty. |
---|
| 213 | */ |
---|
| 214 | object_ptr ( const shared_ptr<T> &b ) : shared_ptr<T> ( b ) { |
---|
| 215 | it_assert_debug ( this->get(), "object_ptr cannot be empty" ); |
---|
| 216 | } |
---|
| 217 | |
---|
| 218 | /*! |
---|
| 219 | Constructs an object_ptr that owns the pointer p. p must |
---|
| 220 | have been alllocated by new! |
---|
| 221 | */ |
---|
| 222 | object_ptr ( T *p ) : shared_ptr<T> ( p ) { |
---|
| 223 | it_assert_debug ( p, "object_ptr cannot be empty" ); |
---|
| 224 | } |
---|
| 225 | |
---|
| 226 | object_ptr<T> &operator= ( const object_ptr<T> &other ) { |
---|
| 227 | shared_ptr<T>::operator= ( other ); |
---|
| 228 | return *this; |
---|
| 229 | } |
---|
| 230 | }; |
---|
| 231 | |
---|
| 232 | #define SHAREDPTR(class_name) typedef bdm::object_ptr< class_name > class_name##_ptr |
---|
| 233 | |
---|
| 234 | #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 |
---|
| 235 | |
---|
[419] | 236 | } |
---|
| 237 | |
---|
| 238 | #endif |
---|