root/library/bdm/shared_ptr.h @ 570

Revision 570, 6.6 kB (checked in by vbarta, 15 years ago)

supporting shared_ptr<const T>

Line 
1/*!
2  \file
3  \brief BDM's own smart pointers.
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>
20#include "bdmerror.h"
21
22namespace bdm {
23
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, \b if it was
30  included in the standard libraries of all supported compilers - but
31  as of 2009, that's still a problem...
32*/
33template <typename T>
34class shared_ptr {
35        template<class U> friend class shared_ptr;
36
37private:
38        T *payload;
39        unsigned *refCnt;
40
41public:
42        /*!
43          \brief Default constructor
44
45          Creates an empty shared_ptr - one that doesn't point anywhere.
46        */
47        shared_ptr() :
48                        payload ( 0 ),
49                        refCnt ( 0 ) {
50        }
51
52        /*!
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        */
58        shared_ptr ( T *p ) :
59                        payload ( p ),
60                        refCnt ( p ? new unsigned ( 1 ) : 0 ) {
61        }
62
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        */
69        shared_ptr ( const shared_ptr<T> &other ) :
70                        payload ( other.payload ),
71                        refCnt ( other.refCnt ) {
72                add_ref();
73        }
74
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        */
84        template<typename U>
85        shared_ptr ( const shared_ptr<U> &other ) :
86                        payload ( other.payload ),
87                        refCnt ( other.refCnt ) {
88                add_ref();
89        }
90
91        /*!
92          Destructor.
93        */
94        ~shared_ptr() {
95                del_ref();
96        }
97
98        /*!
99          \brief Assignment operator
100        */
101        shared_ptr<T> &operator= ( const shared_ptr<T> &other ) {
102                other.add_ref();
103                del_ref();
104
105                payload = other.payload;
106                refCnt = other.refCnt;
107
108                return *this;
109        }
110
111        /*!
112          Returns the stored pointer (which remains owned by this
113          instance). For empty instances, this method returns NULL.
114        */
115        T *get() {
116                return payload;
117        }
118
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        */
124        T *operator->() {
125                bdm_assert_debug ( payload, "dereferencing NULL" );
126                return payload;
127        }
128
129        //! Returns a reference to the object pointed to by the stored
130        //! pointer. This method may only be called when the stored pointer
131        //! isn't NULL.
132        T &operator*() {
133                bdm_assert_debug ( payload, "dereferencing NULL" );
134                return *payload;
135        }
136
137        /*!
138          Returns the stored pointer (which remains owned by this
139          instance). For empty instances, this method returns NULL.
140        */
141        const T* get() const {
142                return payload;
143        }
144
145        //! Returns the stored pointer (which remains owned by this
146        //! instance). This method may only be called when the stored
147        //! pointer isn't NULL.
148        const T *operator->() const {
149                bdm_assert_debug ( payload, "dereferencing NULL" );
150                return payload;
151        }
152
153        //! Returns a reference to the object pointed to by the stored
154        //! pointer. This method may only be called when the stored pointer
155        //! isn't NULL.
156        const T &operator*() const {
157                bdm_assert_debug ( payload, "dereferencing NULL" );
158                return *payload;
159        }
160
161        //! Returns use_count() == 1
162        bool unique() const {
163                return refCnt && ( *refCnt == 1 );
164        }
165
166        /*!
167          Returns the number of shared_ptr instances (including
168          this instance) that share ownership with this instance. For
169          empty instances, this method returns 0.
170        */
171        long use_count() const {
172                return refCnt ? *refCnt : 0;
173        }
174
175        /*!
176          \brief Boolean cast
177
178          This operator returns true if and only if the instance isn't empty.
179        */
180        operator bool() const {
181                return !!payload;
182        }
183
184        /*!
185          \brief const cast
186
187          Shared pointer to T can be converted to shared pointer to
188          const T, just like T * can be converted to T const *.
189        */
190        template<typename U>
191        operator shared_ptr<const U>() const {
192                shared_ptr<const U> cptr;               
193                cptr.refCnt = refCnt;
194                cptr.payload = payload;
195                add_ref();
196                return cptr;
197        }
198
199        /*!
200          \brief Efficient swap for shared_ptr.
201         */
202        void swap ( shared_ptr &other ) {
203                std::swap ( payload, other.payload );
204                std::swap ( refCnt, other.refCnt );
205        }
206
207private:
208        void add_ref() const {
209                if ( refCnt ) {
210                        if ( *refCnt == UINT_MAX ) {
211                                throw std::overflow_error (
212                                    std::string ( "Shared pointer has too many references." ) );
213                        }
214
215                        ++*refCnt;
216                }
217        }
218
219        void del_ref() {
220                if ( refCnt ) {
221                        if ( ! ( --*refCnt ) ) {
222                                delete payload;
223                                delete refCnt;
224                        }
225                }
226        }
227};
228
229//! Compare shared pointers
230template<typename T, typename U>
231bool operator== ( shared_ptr<T> const &a, shared_ptr<U> const &b ) {
232        return a.get() == b.get();
233}
234
235//! Compare shared pointers
236template<typename T, typename U>
237bool operator!= ( shared_ptr<T> const &a, shared_ptr<U> const &b ) {
238        return a.get() != b.get();
239}
240
241//! Compare shared pointers
242template<typename T, typename U>
243bool operator< ( shared_ptr<T> const &a, shared_ptr<U> const &b ) {
244        return a.get() < b.get();
245}
246
247/*! \brief A wrapper of shared_ptr which is never empty.
248
249  T must have a default constructor.
250
251  Note that shared_ptr's destructor isn't virtual - don't call delete
252  on pointers to instances of this class.
253 */
254template <typename T>
255class object_ptr : public shared_ptr<T>
256{
257public:
258        /*!
259          \brief Default constructor
260
261          Calls T's default constructor.
262        */
263        object_ptr() : shared_ptr<T> ( new T() ) { }
264
265        /*!
266          \brief Upcast from shared_ptr<T> to object_ptr<T>
267
268          \param b The shared pointer, which must not be empty.
269        */
270        object_ptr ( const shared_ptr<T> &b ) : shared_ptr<T> ( b ) {
271                bdm_assert_debug ( this->get(), "object_ptr cannot be empty" );
272        }
273
274        /*!
275          Constructs an object_ptr that owns the pointer p. p must
276          have been alllocated by new!
277        */
278        object_ptr ( T *p ) : shared_ptr<T> ( p ) {
279                bdm_assert_debug ( p, "object_ptr cannot be empty" );
280        }
281
282        /*!
283          \brief Assignment operator
284        */
285        object_ptr<T> &operator= ( const object_ptr<T> &other ) {
286                shared_ptr<T>::operator= ( other );
287                return *this;
288        }
289};
290
291#define SHAREDPTR(class_name) typedef bdm::object_ptr< class_name > class_name##_ptr
292
293#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
294
295}
296
297#endif
Note: See TracBrowser for help on using the browser.