containers/smart_ptr.hpp
1: #ifndef STLPLUS_SMART_PTR
2: #define STLPLUS_SMART_PTR
3: ////////////////////////////////////////////////////////////////////////////////
4:
5: // Author: Andy Rushton
6: // Copyright: (c) Southampton University 1999-2004
7: // (c) Andy Rushton 2004-2008
8: // License: BSD License, see ../docs/license.html
9:
10: // A smart pointer is a memory-managing pointer to an object. If you like, it
11: // is a zero-dimensional container.
12:
13: // Assignment of smart pointers result in multiple aliases of the same object.
14: // The term alias is used to differentiate from conventional pointers because
15: // the semantics are different.
16:
17: // Aliases can be turned into copies if the pointed-to class supports copying.
18:
19: // The base class is smart_ptr_base which defines the common interface. Then
20: // there are three subclasses which have the same interface but different copy
21: // semantics:
22:
23: // - smart_ptr for simple types and classes which have copy constructors
24: // - smart_ptr_clone for polymorphic class hierarchies which are copied using a clone method
25: // - smart_ptr_nocopy for any class that cannot or should not be copied
26:
27: ////////////////////////////////////////////////////////////////////////////////
28: #include "containers_fixes.hpp"
29: #include "exceptions.hpp"
30: #include <map>
31: #include <string>
32:
33: namespace stlplus
34: {
35:
36: ////////////////////////////////////////////////////////////////////////////////
37: // internals
38:
39: template<typename T> class smart_ptr_holder;
40:
41: ////////////////////////////////////////////////////////////////////////////////
42: // Base class
43: ////////////////////////////////////////////////////////////////////////////////
44:
45: template<typename T, typename C>
46: class smart_ptr_base
47: {
48: public:
49: //////////////////////////////////////////////////////////////////////////////
50: // member type definitions
51:
52: typedef T value_type;
53: typedef T& reference;
54: typedef const T& const_reference;
55: typedef C value_copy;
56:
57: //////////////////////////////////////////////////////////////////////////////
58: // constructors and destructors
59:
60: // create a null pointer
61: smart_ptr_base(void);
62:
63: // create a pointer containing a *copy* of the object using the template parameter C
64: // this copy is taken because the pointer class maintains a dynamically allocated object
65: // and the T& may not be (usually is not) dynamically allocated
66: explicit smart_ptr_base(const T& data) throw(illegal_copy);
67:
68: // create a pointer containing a dynamically created object
69: // Note: the object must be allocated *by the user* with new
70: // constructor form - must be called in the form smart_ptr_base<type> x(new type(args))
71: explicit smart_ptr_base(T* data);
72:
73: // copy constructor implements aliasing so no copy is made
74: explicit smart_ptr_base(const smart_ptr_base<T,C>& r);
75:
76: // destructor decrements the reference count and delete only when the last reference is destroyed
77: ~smart_ptr_base(void);
78:
79: //////////////////////////////////////////////////////////////////////////////
80: // logical tests to see if there is anything contained in the pointer since it can be null
81:
82: // there are two forms:explicit and implicit
83: // implicit: if(!r) or if(r)
84: // explicit: if(r.null()) or if(r.present())
85: operator bool(void) const;
86: bool operator!(void) const;
87: bool present(void) const;
88: bool null(void) const;
89:
90: //////////////////////////////////////////////////////////////////////////////
91: // dereference operators and functions
92:
93: // dereference the smart pointer to get the object - use in the form *p1
94: T& operator*(void) throw(null_dereference);
95: const T& operator*(void) const throw(null_dereference);
96:
97: // used as a prefix to a member access to the contained object e.g. p1->print() calls T::print()
98: T* operator->(void) throw(null_dereference);
99: const T* operator->(void) const throw(null_dereference);
100:
101: //////////////////////////////////////////////////////////////////////////////
102: // explicit function forms of the above assignment and dereference operators
103:
104: // set the value - note that this does a copy using the C template parameter
105: void set_value(const T& data) throw(illegal_copy);
106: // get the value
107: T& value(void) throw(null_dereference);
108: const T& value(void) const throw(null_dereference);
109:
110: // set the pointer
111: // deletes the previous pointer and adopts the passed pointer instead
112: // Note: the object must be allocated *by the user* with new
113: // Warning: it is very easy to break the memory management with this operation
114: void set(T* data = 0);
115: // get the pointer
116: T* pointer(void);
117: const T* pointer(void) const;
118:
119: //////////////////////////////////////////////////////////////////////////////
120: // functions to manage aliases
121:
122: // make this an alias of the passed object
123: void alias(const smart_ptr_base<T,C>&);
124:
125: // test whether two pointers point to the same object(known as aliasing the object)
126: // used in the form if(a.aliases(b))
127: bool aliases(const smart_ptr_base<T,C>&) const;
128:
129: // find the number of aliases - used when you need to know whether an
130: // object is still referred to from elsewhere (rare!)
131: unsigned alias_count(void) const;
132:
133: // delete the object and make the pointer null - does not make it unique
134: // first, so all other pointers to this will be null too
135: void clear(void);
136:
137: // make the pointer unique and null in one step - does not affect other
138: // pointers that were pointing to the same object
139: void clear_unique(void);
140:
141: //////////////////////////////////////////////////////////////////////////////
142: // functions that involve copying
143:
144: // these functions use the copy functor passed as the template parameter C
145: // to copy the object with the right copy semantics. If the copy functor
146: // is no_copy, an exception will be thrown.
147:
148: // make this pointer unique with respect to any other references to the same object
149: // if this pointer is already unique, it does nothing - otherwise it copies the object
150: void make_unique(void) throw(illegal_copy);
151:
152: // make this pointer a unique copy of the parameter
153: // useful for expressions like p1.copy(p2) which makes p1 a pointer to a unique copy of the contents of p2
154: void copy(const smart_ptr_base<T,C>&) throw(illegal_copy);
155:
156: protected:
157: smart_ptr_holder<T>* m_holder;
158:
159: public:
160: // internal use only - had to make them public because they need to be
161: // accessed by routines that could not be made friends
162: void* handle(void) const;
163: void make_alias(void* handle);
164: };
165:
166: ////////////////////////////////////////////////////////////////////////////////
167: // copy functors implementing the three possible copy semantics
168:
169: // constructor_copy uses the copy constructor of the object - used for simple types
170:
171: template <typename T>
172: class constructor_copy
173: {
174: public:
175: T* operator() (const T& from) throw()
176: {
177: return new T(from);
178: }
179: };
180:
181: // clone_copy uses the clone method of the object - used for polymorphic types
182:
183: template <typename T>
184: class clone_copy
185: {
186: public:
187: T* operator() (const T& from) throw()
188: {
189: return from.clone();
190: }
191: };
192:
193: // no_copy throws an exception - used for types that cannot be copied
194:
195: template <typename T>
196: class no_copy
197: {
198: public:
199: T* operator() (const T& from) throw(illegal_copy)
200: {
201: throw illegal_copy("no_copy functor called");
202: return 0;
203: }
204: };
205:
206: ////////////////////////////////////////////////////////////////////////////////
207: // smart_ptr for simple types and classes which have copy constructors
208:
209: template <typename T>
210: class smart_ptr : public smart_ptr_base<T, constructor_copy<T> >
211: {
212: public:
213: smart_ptr(void) {}
214: explicit smart_ptr(const T& data) : smart_ptr_base<T, constructor_copy<T> >(data) {}
215: explicit smart_ptr(T* data) : smart_ptr_base<T, constructor_copy<T> >(data) {}
216: smart_ptr<T>& operator=(const T& data) {set_value(data); return *this;}
217: smart_ptr<T>& operator=(const smart_ptr<T>& r) {alias(r); return *this;}
218: ~smart_ptr(void) {}
219: };
220:
221: ////////////////////////////////////////////////////////////////////////////////
222: // smart_ptr_clone for polymorphic class hierarchies which have a clone method
223:
224: template <typename T>
225: class smart_ptr_clone : public smart_ptr_base<T, clone_copy<T> >
226: {
227: public:
228: smart_ptr_clone(void) {}
229: explicit smart_ptr_clone(const T& data) : smart_ptr_base<T, clone_copy<T> >(data) {}
230: explicit smart_ptr_clone(T* data) : smart_ptr_base<T, clone_copy<T> >(data) {}
231: smart_ptr_clone<T>& operator=(const T& data) {set_value(data); return *this;}
232: smart_ptr_clone<T>& operator=(const smart_ptr_clone<T>& r) {alias(r); return *this;}
233: ~smart_ptr_clone(void) {}
234: };
235:
236: ////////////////////////////////////////////////////////////////////////////////
237: // smart_ptr_nocopy for any class that cannot or should not be copied
238:
239: template <typename T>
240: class smart_ptr_nocopy : public smart_ptr_base<T, no_copy<T> >
241: {
242: public:
243: smart_ptr_nocopy(void) {}
244: explicit smart_ptr_nocopy(const T& data) : smart_ptr_base<T, no_copy<T> >(data) {}
245: explicit smart_ptr_nocopy(T* data) : smart_ptr_base<T, no_copy<T> >(data) {}
246: smart_ptr_nocopy<T>& operator=(const T& data) {set_value(data); return *this;}
247: smart_ptr_nocopy<T>& operator=(const smart_ptr_nocopy<T>& r) {alias(r); return *this;}
248: ~smart_ptr_nocopy(void) {}
249: };
250:
251: ////////////////////////////////////////////////////////////////////////////////
252:
253: } // end namespace stlplus
254:
255: #include "smart_ptr.tpp"
256: #endif