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-2009
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 "copy_functors.hpp"
31: #include <map>
32: #include <string>
33:
34: namespace stlplus
35: {
36:
37: ////////////////////////////////////////////////////////////////////////////////
38: // internals
39:
40: template<typename T> class smart_ptr_holder;
41:
42: ////////////////////////////////////////////////////////////////////////////////
43: // Base class
44: ////////////////////////////////////////////////////////////////////////////////
45:
46: template<typename T, typename C>
47: class smart_ptr_base
48: {
49: public:
50: //////////////////////////////////////////////////////////////////////////////
51: // member type definitions
52:
53: typedef T value_type;
54: typedef T& reference;
55: typedef const T& const_reference;
56: typedef C value_copy;
57:
58: //////////////////////////////////////////////////////////////////////////////
59: // constructors and destructors
60:
61: // create a null pointer
62: smart_ptr_base(void);
63:
64: // create a pointer containing a *copy* of the object using the template parameter C
65: // this copy is taken because the pointer class maintains a dynamically allocated object
66: // and the T& may not be (usually is not) dynamically allocated
67: explicit smart_ptr_base(const T& data) throw(illegal_copy);
68:
69: // create a pointer containing a dynamically created object
70: // Note: the object must be allocated *by the user* with new
71: // constructor form - must be called in the form smart_ptr_base<type> x(new type(args))
72: explicit smart_ptr_base(T* data);
73:
74: // copy constructor implements aliasing so no copy is made
75: // note that the copy constructor should NOT be explicit, as this breaks
76: // the returning of pointer objects from functions (at least within GCC 4.4)
77: smart_ptr_base(const smart_ptr_base<T,C>& r);
78:
79: // assignment operator - required, else the output of GCC suffers segmentation faults
80: smart_ptr_base<T,C>& operator=(const smart_ptr_base<T,C>& r);
81:
82: // destructor decrements the reference count and delete only when the last reference is destroyed
83: ~smart_ptr_base(void);
84:
85: //////////////////////////////////////////////////////////////////////////////
86: // logical tests to see if there is anything contained in the pointer since it can be null
87:
88: // there are two forms:explicit and implicit
89: // implicit: if(!r) or if(r)
90: // explicit: if(r.null()) or if(r.present())
91: operator bool(void) const;
92: bool operator!(void) const;
93: bool present(void) const;
94: bool null(void) const;
95:
96: //////////////////////////////////////////////////////////////////////////////
97: // dereference operators and functions
98:
99: // dereference the smart pointer to get the object - use in the form *p1
100: T& operator*(void) throw(null_dereference);
101: const T& operator*(void) const throw(null_dereference);
102:
103: // used as a prefix to a member access to the contained object e.g. p1->print() calls T::print()
104: T* operator->(void) throw(null_dereference);
105: const T* operator->(void) const throw(null_dereference);
106:
107: //////////////////////////////////////////////////////////////////////////////
108: // explicit function forms of the above assignment and dereference operators
109:
110: // set the value - note that this does a copy using the C template parameter
111: void set_value(const T& data) throw(illegal_copy);
112: // get the value
113: T& value(void) throw(null_dereference);
114: const T& value(void) const throw(null_dereference);
115:
116: // set the pointer
117: // deletes the previous pointer and adopts the passed pointer instead
118: // Note: the object must be allocated *by the user* with new
119: // Warning: it is very easy to break the memory management with this operation
120: void set(T* data = 0);
121: // get the pointer
122: T* pointer(void);
123: const T* pointer(void) const;
124:
125: //////////////////////////////////////////////////////////////////////////////
126: // functions to manage aliases
127:
128: // make this an alias of the passed object
129: void alias(const smart_ptr_base<T,C>&);
130:
131: // test whether two pointers point to the same object(known as aliasing the object)
132: // used in the form if(a.aliases(b))
133: bool aliases(const smart_ptr_base<T,C>&) const;
134:
135: // find the number of aliases - used when you need to know whether an
136: // object is still referred to from elsewhere (rare!)
137: unsigned alias_count(void) const;
138:
139: // delete the object and make the pointer null - does not make it unique
140: // first, so all other pointers to this will be null too
141: void clear(void);
142:
143: // make the pointer unique and null in one step - does not affect other
144: // pointers that were pointing to the same object
145: void clear_unique(void);
146:
147: //////////////////////////////////////////////////////////////////////////////
148: // functions that involve copying
149:
150: // these functions use the copy functor passed as the template parameter C
151: // to copy the object with the right copy semantics. If the copy functor
152: // is no_copy, an exception will be thrown.
153:
154: // make this pointer unique with respect to any other references to the same object
155: // if this pointer is already unique, it does nothing - otherwise it copies the object
156: void make_unique(void) throw(illegal_copy);
157:
158: // make this pointer a unique copy of the parameter
159: // useful for expressions like p1.copy(p2) which makes p1 a pointer to a unique copy of the contents of p2
160: void copy(const smart_ptr_base<T,C>&) throw(illegal_copy);
161:
162: protected:
163: smart_ptr_holder<T>* m_holder;
164:
165: public:
166: // internal use only - had to make them public because they need to be
167: // accessed by routines that could not be made friends
168: smart_ptr_holder<T>* _handle(void) const;
169: void _make_alias(smart_ptr_holder<T>* handle);
170: };
171:
172: ////////////////////////////////////////////////////////////////////////////////
173: // smart_ptr for simple types and classes which have copy constructors
174:
175: template <typename T>
176: class smart_ptr : public smart_ptr_base<T, constructor_copy<T> >
177: {
178: public:
179: smart_ptr(void) {}
180: explicit smart_ptr(const T& data) : smart_ptr_base<T, constructor_copy<T> >(data) {}
181: explicit smart_ptr(T* data) : smart_ptr_base<T, constructor_copy<T> >(data) {}
182: smart_ptr<T>& operator=(const T& data) {set_value(data); return *this;}
183: smart_ptr<T>& operator=(T* data) {set(data); return *this;}
184: ~smart_ptr(void) {}
185: };
186:
187: ////////////////////////////////////////////////////////////////////////////////
188: // smart_ptr_clone for polymorphic class hierarchies which have a clone method
189:
190: template <typename T>
191: class smart_ptr_clone : public smart_ptr_base<T, clone_copy<T> >
192: {
193: public:
194: smart_ptr_clone(void) {}
195: explicit smart_ptr_clone(const T& data) : smart_ptr_base<T, clone_copy<T> >(data) {}
196: explicit smart_ptr_clone(T* data) : smart_ptr_base<T, clone_copy<T> >(data) {}
197: smart_ptr_clone<T>& operator=(const T& data) {set_value(data); return *this;}
198: smart_ptr_clone<T>& operator=(T* data) {set(data); return *this;}
199: ~smart_ptr_clone(void) {}
200: };
201:
202: ////////////////////////////////////////////////////////////////////////////////
203: // smart_ptr_nocopy for any class that cannot or should not be copied
204:
205: template <typename T>
206: class smart_ptr_nocopy : public smart_ptr_base<T, no_copy<T> >
207: {
208: public:
209: smart_ptr_nocopy(void) {}
210: explicit smart_ptr_nocopy(const T& data) : smart_ptr_base<T, no_copy<T> >(data) {}
211: explicit smart_ptr_nocopy(T* data) : smart_ptr_base<T, no_copy<T> >(data) {}
212: smart_ptr_nocopy<T>& operator=(const T& data) {set_value(data); return *this;}
213: smart_ptr_nocopy<T>& operator=(T* data) {set(data); return *this;}
214: ~smart_ptr_nocopy(void) {}
215: };
216:
217: ////////////////////////////////////////////////////////////////////////////////
218:
219: } // end namespace stlplus
220:
221: #include "smart_ptr.tpp"
222: #endif