1 ////////////////////////////////////////////////////////////////////////////////
3 // Author: Andy Rushton
4 // Copyright: (c) Southampton University 1999-2004
5 // (c) Andy Rushton 2004-2009
6 // License: BSD License, see ../docs/license.html
8 ////////////////////////////////////////////////////////////////////////////////
13 ////////////////////////////////////////////////////////////////////////////////
14 // internal holder data structure
15 ////////////////////////////////////////////////////////////////////////////////
18 class smart_ptr_holder
24 // make these private to disallow copying because the holder doesn't know how to copy
25 smart_ptr_holder(const smart_ptr_holder& s) :
30 smart_ptr_holder& operator=(const smart_ptr_holder& s)
36 smart_ptr_holder(T* p = 0) :
41 ~smart_ptr_holder(void)
46 unsigned count(void) const
85 const T* pointer(void) const
95 const T& value(void) const
101 ////////////////////////////////////////////////////////////////////////////////
102 // smart_ptr_base class
103 ////////////////////////////////////////////////////////////////////////////////
105 ////////////////////////////////////////////////////////////////////////////////
106 // constructors, assignments and destructors
108 // create a null pointer
109 template <typename T, typename C>
110 smart_ptr_base<T,C>::smart_ptr_base(void) :
111 m_holder(new smart_ptr_holder<T>)
115 // create a pointer containing a *copy* of the object pointer
116 template <typename T, typename C>
117 smart_ptr_base<T,C>::smart_ptr_base(const T& data) throw(illegal_copy) :
118 m_holder(new smart_ptr_holder<T>)
120 m_holder->set(C()(data));
123 // create a pointer containing a dynamically created object
124 // Note: the object must be allocated *by the user* with new
125 // constructor form - must be called in the form smart_ptr<type> x(new type(args))
126 template <typename T, typename C>
127 smart_ptr_base<T,C>::smart_ptr_base(T* data) :
128 m_holder(new smart_ptr_holder<T>)
133 // copy constructor implements counted referencing - no copy is made
134 template <typename T, typename C>
135 smart_ptr_base<T,C>::smart_ptr_base(const smart_ptr_base<T,C>& r) :
138 m_holder = r.m_holder;
139 m_holder->increment();
142 // assignment operator - required, else the output of GCC suffers segmentation faults
143 template <typename T, typename C>
144 smart_ptr_base<T,C>& smart_ptr_base<T,C>::operator=(const smart_ptr_base<T,C>& r)
150 // destructor decrements the reference count and delete only when the last reference is destroyed
151 template <typename T, typename C>
152 smart_ptr_base<T,C>::~smart_ptr_base(void)
154 if(m_holder->decrement())
158 //////////////////////////////////////////////////////////////////////////////
159 // logical tests to see if there is anything contained in the pointer since it can be null
161 template <typename T, typename C>
162 bool smart_ptr_base<T,C>::null(void) const
164 return m_holder->null();
167 template <typename T, typename C>
168 bool smart_ptr_base<T,C>::present(void) const
170 return !m_holder->null();
173 template <typename T, typename C>
174 bool smart_ptr_base<T,C>::operator!(void) const
176 return m_holder->null();
179 template <typename T, typename C>
180 smart_ptr_base<T,C>::operator bool(void) const
182 return !m_holder->null();
185 //////////////////////////////////////////////////////////////////////////////
186 // dereference operators and functions
188 template <typename T, typename C>
189 T& smart_ptr_base<T,C>::operator*(void) throw(null_dereference)
191 if (m_holder->null()) throw null_dereference("null pointer dereferenced in smart_ptr::operator*");
192 return m_holder->value();
195 template <typename T, typename C>
196 const T& smart_ptr_base<T,C>::operator*(void) const throw(null_dereference)
198 if (m_holder->null()) throw null_dereference("null pointer dereferenced in smart_ptr::operator*");
199 return m_holder->value();
202 template <typename T, typename C>
203 T* smart_ptr_base<T,C>::operator->(void) throw(null_dereference)
205 if (m_holder->null()) throw null_dereference("null pointer dereferenced in smart_ptr::operator->");
206 return m_holder->pointer();
209 template <typename T, typename C>
210 const T* smart_ptr_base<T,C>::operator->(void) const throw(null_dereference)
212 if (m_holder->null()) throw null_dereference("null pointer dereferenced in smart_ptr::operator->");
213 return m_holder->pointer();
216 //////////////////////////////////////////////////////////////////////////////
217 // explicit function forms of the above assignment dereference operators
219 template <typename T, typename C>
220 void smart_ptr_base<T,C>::set_value(const T& data) throw(illegal_copy)
222 m_holder->set(C()(data));
225 template <typename T, typename C>
226 T& smart_ptr_base<T,C>::value(void) throw(null_dereference)
228 if (m_holder->null()) throw null_dereference("null pointer dereferenced in smart_ptr::value");
229 return m_holder->value();
232 template <typename T, typename C>
233 const T& smart_ptr_base<T,C>::value(void) const throw(null_dereference)
235 if (m_holder->null()) throw null_dereference("null pointer dereferenced in smart_ptr::value");
236 return m_holder->value();
239 template <typename T, typename C>
240 void smart_ptr_base<T,C>::set(T* data)
245 template <typename T, typename C>
246 T* smart_ptr_base<T,C>::pointer(void)
248 return m_holder->pointer();
251 template <typename T, typename C>
252 const T* smart_ptr_base<T,C>::pointer(void) const
254 return m_holder->pointer();
257 ////////////////////////////////////////////////////////////////////////////////
258 // functions to manage counted referencing
260 // make this an alias of the passed object
261 template <typename T, typename C>
262 void smart_ptr_base<T,C>::alias(const smart_ptr_base<T,C>& r)
264 _make_alias(r.m_holder);
267 template <typename T, typename C>
268 bool smart_ptr_base<T,C>::aliases(const smart_ptr_base<T,C>& r) const
270 return m_holder == r.m_holder;
273 template <typename T, typename C>
274 unsigned smart_ptr_base<T,C>::alias_count(void) const
276 return m_holder->count();
279 template <typename T, typename C>
280 void smart_ptr_base<T,C>::clear(void)
285 template <typename T, typename C>
286 void smart_ptr_base<T,C>::clear_unique(void)
288 if (m_holder->count() == 1)
292 m_holder->decrement();
294 m_holder = new smart_ptr_holder<T>;
298 template <typename T, typename C>
299 void smart_ptr_base<T,C>::make_unique(void) throw(illegal_copy)
301 if (m_holder->count() > 1)
303 smart_ptr_holder<T>* old_holder = m_holder;
304 m_holder->decrement();
306 m_holder = new smart_ptr_holder<T>;
307 if (old_holder->pointer())
308 m_holder->set(C()(old_holder->value()));
312 template <typename T, typename C>
313 void smart_ptr_base<T,C>::copy(const smart_ptr_base<T,C>& data) throw(illegal_copy)
319 // internal function for distinguishing unique smart_ptr objects
320 // used for example in persistence routines
322 template <typename T, typename C>
323 smart_ptr_holder<T>* smart_ptr_base<T,C>::_handle(void) const
328 template <typename T, typename C>
329 void smart_ptr_base<T,C>::_make_alias(smart_ptr_holder<T>* r_holder)
331 // make it alias-copy safe - this means that I don't try to do the
332 // assignment if r is either the same object or an alias of it
333 if (m_holder != r_holder)
335 if (m_holder->decrement())
338 m_holder->increment();
342 ////////////////////////////////////////////////////////////////////////////////
344 } // end namespace stlplus