ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/utils/SmartPointer.hpp
Revision: 1492
Committed: Mon Aug 16 18:07:50 2010 UTC (14 years, 8 months ago) by chuckv
File size: 9368 byte(s)
Log Message:
Adding exception and reporting mechanism from ProtoMol to OpenMD.

File Contents

# Content
1 /*******************************************************************\
2
3 Copyright (C) 2003 Joseph Coffland
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18 02111-1307, USA.
19
20 For information regarding this software email
21 jcofflan@users.sourceforge.net
22
23 \*******************************************************************/
24
25 #include "utils/Exception.hpp"
26
27 #ifndef UTILS_SMARTPOINTER_H
28 #define UTILS_SMARTPOINTER_H
29
30 #include "utils/Counter.hpp"
31
32 #include <stdlib.h>
33
34
35 namespace OpenMD {
36 // Forward Delcarations
37 class Exception;
38
39 // Deallocators
40 template <class T>
41 struct SP_NEW {static void dealloc(T *ptr) {delete ptr;}};
42
43 template <class T>
44 struct SP_ARRAY {static void dealloc(T *ptr) {delete [] ptr;}};
45
46 struct SP_MALLOC {static void dealloc(void *ptr) {free(ptr);}};
47
48 template <void (*Func)(void *)>
49 struct SP_FUNC {static void dealloc(void *ptr) {Func(ptr);}};
50
51 /**
52 * This class is an implementation of a smart pointer. IT IS NOT
53 * THREAD SAFE. This means that you cannot use SmartPointers
54 * to the same data in different threads. Even if you make a new
55 * copy of the smart pointer. This is because they will still share
56 * the same Counter. However, SmartPointer
57 * is faster because it is not thread safe.
58 *
59 * You can use a SmartPointer on a dynamic instance of a class A as
60 * follows.
61 *
62 * SmartPointer<A> aPtr = new A;
63 *
64 * Since aPtr is static when it goes out of scope it will be destructed.
65 * When this happens the reference counter will be decremented and if
66 * it is zero the dynamic instance of A will be destructed.
67 *
68 * You can make a copy of a smart pointer as follows.
69 *
70 * SmartPointer<A> anotherPtr = aPtr;
71 *
72 * Now the dynamic instance of A will not be destructed until both
73 * aPtr and anotherPtr go out of scope.
74 *
75 * Correct deallocation can vary depending on the type of resource being
76 * protected by the smart pointer. The DEALLOC_T template parameter selects
77 * the deallocator. The default deallocator is used for any data allocated
78 * with the 'new' operator. SP_ARRAY is necessary for arrays allocated with
79 * the 'new []' operator. SP_MALLOC will correctly deallocate data allocated
80 * with calls to 'malloc', 'calloc', 'realloc', et.al.
81 *
82 * You can also create your own deallocators for other resources. The
83 * managed resources need not even be memory.
84 *
85 * See http://ootips.org/yonat/4dev/smart-pointers.html for more information
86 * about smart pointers and why to use them.
87 */
88 template <class T, class DEALLOC_T = SP_NEW<T> >
89 class SmartPointer {
90 /// A pointer to the reference counter.
91 Counter *refCounter;
92
93 /// The actual pointer.
94 T *ptr;
95
96 public:
97 typedef SmartPointer<T, DEALLOC_T> SmartPointer_T;
98 typedef SmartPointer<T, SP_ARRAY<T> > Array;
99
100 /**
101 * Create a NULL smart pointer
102 *
103 */
104 SmartPointer() : refCounter(0), ptr(0) {}
105
106 /**
107 * The copy constructor. If the smart pointer being copied
108 * is not NULL the object reference count will be incremented.
109 *
110 * @param smartPtr The pointer to copy.
111 */
112 SmartPointer(const SmartPointer_T &smartPtr) :
113 refCounter(0), ptr(0) {
114 *this = smartPtr;
115 }
116
117 /**
118 * Create a smart pointer from a pointer value. If ptr is
119 * non-NULL the reference count will be set to one.
120 * NOTE: It is an error to create more than one smart pointer
121 * through this constructor for a single pointer value because
122 * this will cause the object
123 * to which it points to be deallocated more than once. To create
124 * a copy of a smart pointer either use the copy constructor or
125 * the smart pointer assignment operator.
126 *
127 * @param ptr The pointer to point to.
128 */
129 SmartPointer(T *ptr) : refCounter(0), ptr(0) {
130 if (ptr) {
131 refCounter = new Counter(1);
132 this->ptr = ptr;
133 }
134 }
135
136 /**
137 * Destroy this smart pointer. If this smart pointer is set to
138 * a non-NULL value and there are no other references to the
139 * object to which it points the object will be deleted.
140 */
141 ~SmartPointer() {release();}
142
143 /**
144 * Compare two smart pointers for equality. Two smart pointers
145 * are equal if and only if their internal pointers are equal.
146 *
147 * @param smartPtr The pointer to compare with.
148 *
149 * @return True if the smart pointers are equal. False otherwise.
150 */
151 const bool operator==(const SmartPointer_T &smartPtr) const {
152 return ptr == smartPtr.ptr;
153 }
154
155
156 /**
157 * Compare two smart pointers for inequality. Two smart pointers
158 * are not equal if and only if their internal pointers are not equal.
159 *
160 * @param smartPtr The pointer to compare with.
161 *
162 * @return True if the smart pointers are not equal. False otherwise.
163 */
164 const bool operator!=(const SmartPointer_T &smartPtr) const {
165 return ptr != smartPtr.ptr;
166 }
167
168 /**
169 * Compare this smart pointer to an actual pointer value.
170 *
171 * @param ptr The pointer to compare with.
172 *
173 * @return True if this smart pointers internal pointer equals ptr.
174 * False otherwise.
175 */
176 const bool operator==(const T *ptr) {
177 return this->ptr == ptr;
178 }
179
180 /**
181 * Asign this smart pointer to another. If the passed smart pointer
182 * is non-NULL a reference will be added.
183 *
184 * @param smartPtr The pointer to copy.
185 *
186 * @return A reference to this smart pointer.
187 */
188 SmartPointer_T &operator=(const SmartPointer_T &smartPtr) {
189 if (*this == smartPtr) return *this;
190
191 release();
192
193 refCounter = smartPtr.refCounter;
194 if (refCounter) refCounter->inc();
195 ptr = smartPtr.ptr;
196
197 return *this;
198 }
199
200 /**
201 * Dereference this smart pointer.
202 * A Exception will be thrown if this smart pointer is NULL.
203 *
204 * @return A reference to the object pointed to by this smart pointer.
205 */
206 T *operator->() const {checkPtr(); return get();}
207
208 /**
209 * Dereference this smart pointer.
210 * A Exception will be thrown if this smart pointer is NULL.
211 *
212 * @return A reference to the object pointed to by this smart pointer.
213 */
214 T &operator*() const {checkPtr(); return *get();}
215
216 /**
217 * Dereference this smart pointer with an array index.
218 * A Exception will be thrown if this smart pointer is NULL.
219 *
220 * @return A reference to an object in the array pointed to by
221 * this smart pointer.
222 */
223 T &operator[](const long x) const {checkPtr(); return get()[x];}
224
225 /**
226 * Access this smart pointers internal object pointer;
227 *
228 * @return The value of the internal object pointer;
229 */
230 T *get() const {return ptr;}
231
232 /// Not operator
233 bool operator!() const {return ptr == 0;}
234
235 /**
236 * Release this smart pointer's reference.
237 * If the reference count is one the object to which this
238 * smart pointer points will be deleted.
239 */
240 void release() {
241 if (refCounter && !refCounter->dec()) {
242 delete refCounter;
243 DEALLOC_T::dealloc(ptr);
244 }
245
246 refCounter = 0;
247 ptr = 0;
248 }
249
250 /**
251 * Assume responsibility for this pointer. If the reference
252 * counter is more than one a Exception will be thrown.
253 * When successful this smart pointer will be NULL.
254 *
255 * This function can be useful for moving the pointer to
256 * a base class smart pointer.
257 *
258 * @return The value of the internal pointer.
259 */
260 T *adopt() {
261 if (refCounter && refCounter->getCount() > 1)
262 throw Exception
263 ("SmartPointer: Cannot adopt a pointer with multiple references!");
264
265 if (refCounter) {
266 delete refCounter;
267 refCounter = 0;
268 }
269 T *tmp = ptr;
270 ptr = 0;
271
272 return tmp;
273 }
274
275 /**
276 * Get the number of references to the object pointed to by
277 * this smart pointer. The reference count will be zero
278 * if this is a NULL smart pointer other wise it will be
279 * one or more.
280 *
281 * @return The reference count.
282 */
283 long getRefCount() const {return refCounter ? refCounter->getCount() : 0;}
284
285 /**
286 * Check for NULL pointer value;
287 *
288 * @return True if the internal pointer is NULL. False otherwise.
289 */
290 bool isNull() const {return get() == 0;}
291
292 protected:
293 void checkPtr() const {
294 if (!ptr)
295 throw Exception("SmartPointer: Can't dereference a NULL pointer!");
296 }
297 };
298 }
299 #endif // SMARTPOINTER_H