1 | // |
2 | // AutoPtr.h |
3 | // |
4 | // Library: Foundation |
5 | // Package: Core |
6 | // Module: AutoPtr |
7 | // |
8 | // Definition of the AutoPtr template class. |
9 | // |
10 | // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. |
11 | // and Contributors. |
12 | // |
13 | // SPDX-License-Identifier: BSL-1.0 |
14 | // |
15 | |
16 | |
17 | #ifndef Foundation_AutoPtr_INCLUDED |
18 | #define Foundation_AutoPtr_INCLUDED |
19 | |
20 | |
21 | #include "Poco/Foundation.h" |
22 | #include "Poco/Exception.h" |
23 | #include <algorithm> |
24 | |
25 | |
26 | namespace Poco { |
27 | |
28 | |
29 | template <class C> |
30 | class AutoPtr |
31 | /// AutoPtr is a "smart" pointer for classes implementing |
32 | /// reference counting based garbage collection. |
33 | /// To be usable with the AutoPtr template, a class must |
34 | /// implement the following behaviour: |
35 | /// A class must maintain a reference count. |
36 | /// The constructors of the object initialize the reference |
37 | /// count to one. |
38 | /// The class must implement a public duplicate() method: |
39 | /// void duplicate(); |
40 | /// that increments the reference count by one. |
41 | /// The class must implement a public release() method: |
42 | /// void release() |
43 | /// that decrements the reference count by one, and, |
44 | /// if the reference count reaches zero, deletes the |
45 | /// object. |
46 | /// |
47 | /// AutoPtr works in the following way: |
48 | /// If an AutoPtr is assigned an ordinary pointer to |
49 | /// an object (via the constructor or the assignment operator), |
50 | /// it takes ownership of the object and the object's reference |
51 | /// count remains unchanged. |
52 | /// If the AutoPtr is assigned another AutoPtr, the |
53 | /// object's reference count is incremented by one by |
54 | /// calling duplicate() on its object. |
55 | /// The destructor of AutoPtr calls release() on its |
56 | /// object. |
57 | /// AutoPtr supports dereferencing with both the -> |
58 | /// and the * operator. An attempt to dereference a null |
59 | /// AutoPtr results in a NullPointerException being thrown. |
60 | /// AutoPtr also implements all relational operators. |
61 | /// Note that AutoPtr allows casting of its encapsulated data types. |
62 | { |
63 | public: |
64 | AutoPtr(): _ptr(0) |
65 | { |
66 | } |
67 | |
68 | AutoPtr(C* ptr): _ptr(ptr) |
69 | { |
70 | } |
71 | |
72 | AutoPtr(C* ptr, bool shared): _ptr(ptr) |
73 | { |
74 | if (shared && _ptr) _ptr->duplicate(); |
75 | } |
76 | |
77 | AutoPtr(const AutoPtr& ptr): _ptr(ptr._ptr) |
78 | { |
79 | if (_ptr) _ptr->duplicate(); |
80 | } |
81 | |
82 | AutoPtr(AutoPtr&& ptr) : _ptr(std::move(ptr._ptr)) |
83 | { |
84 | ptr._ptr = nullptr; |
85 | } |
86 | |
87 | template <class Other> |
88 | AutoPtr(const AutoPtr<Other>& ptr): _ptr(const_cast<Other*>(ptr.get())) |
89 | { |
90 | if (_ptr) _ptr->duplicate(); |
91 | } |
92 | |
93 | ~AutoPtr() |
94 | { |
95 | if (_ptr) _ptr->release(); |
96 | } |
97 | |
98 | AutoPtr& assign(C* ptr) |
99 | { |
100 | if (_ptr != ptr) |
101 | { |
102 | if (_ptr) _ptr->release(); |
103 | _ptr = ptr; |
104 | } |
105 | return *this; |
106 | } |
107 | |
108 | AutoPtr& assign(C* ptr, bool shared) |
109 | { |
110 | if (_ptr != ptr) |
111 | { |
112 | if (_ptr) _ptr->release(); |
113 | _ptr = ptr; |
114 | if (shared && _ptr) _ptr->duplicate(); |
115 | } |
116 | return *this; |
117 | } |
118 | |
119 | AutoPtr& assign(const AutoPtr& ptr) |
120 | { |
121 | if (&ptr != this) |
122 | { |
123 | if (_ptr) _ptr->release(); |
124 | _ptr = ptr._ptr; |
125 | if (_ptr) _ptr->duplicate(); |
126 | } |
127 | return *this; |
128 | } |
129 | |
130 | template <class Other> |
131 | AutoPtr& assign(const AutoPtr<Other>& ptr) |
132 | { |
133 | if (ptr.get() != _ptr) |
134 | { |
135 | if (_ptr) _ptr->release(); |
136 | _ptr = const_cast<Other*>(ptr.get()); |
137 | if (_ptr) _ptr->duplicate(); |
138 | } |
139 | return *this; |
140 | } |
141 | |
142 | AutoPtr& operator = (C* ptr) |
143 | { |
144 | return assign(ptr); |
145 | } |
146 | |
147 | AutoPtr& operator = (const AutoPtr& ptr) |
148 | { |
149 | return assign(ptr); |
150 | } |
151 | |
152 | template <class Other> |
153 | AutoPtr& operator = (const AutoPtr<Other>& ptr) |
154 | { |
155 | return assign<Other>(ptr); |
156 | } |
157 | |
158 | AutoPtr& operator = (AutoPtr&& ptr) |
159 | { |
160 | swap(ptr); |
161 | return *this; |
162 | } |
163 | |
164 | |
165 | void swap(AutoPtr& ptr) |
166 | { |
167 | std::swap(_ptr, ptr._ptr); |
168 | } |
169 | |
170 | template <class Other> |
171 | AutoPtr<Other> cast() const |
172 | /// Casts the AutoPtr via a dynamic cast to the given type. |
173 | /// Returns an AutoPtr containing NULL if the cast fails. |
174 | /// Example: (assume class Sub: public Super) |
175 | /// AutoPtr<Super> super(new Sub()); |
176 | /// AutoPtr<Sub> sub = super.cast<Sub>(); |
177 | /// poco_assert (sub.get()); |
178 | { |
179 | Other* pOther = dynamic_cast<Other*>(_ptr); |
180 | return AutoPtr<Other>(pOther, true); |
181 | } |
182 | |
183 | template <class Other> |
184 | AutoPtr<Other> unsafeCast() const |
185 | /// Casts the AutoPtr via a static cast to the given type. |
186 | /// Example: (assume class Sub: public Super) |
187 | /// AutoPtr<Super> super(new Sub()); |
188 | /// AutoPtr<Sub> sub = super.unsafeCast<Sub>(); |
189 | /// poco_assert (sub.get()); |
190 | { |
191 | Other* pOther = static_cast<Other*>(_ptr); |
192 | return AutoPtr<Other>(pOther, true); |
193 | } |
194 | |
195 | C* operator -> () |
196 | { |
197 | if (_ptr) |
198 | return _ptr; |
199 | else |
200 | throw NullPointerException(); |
201 | } |
202 | |
203 | const C* operator -> () const |
204 | { |
205 | if (_ptr) |
206 | return _ptr; |
207 | else |
208 | throw NullPointerException(); |
209 | } |
210 | |
211 | C& operator * () |
212 | { |
213 | if (_ptr) |
214 | return *_ptr; |
215 | else |
216 | throw NullPointerException(); |
217 | } |
218 | |
219 | const C& operator * () const |
220 | { |
221 | if (_ptr) |
222 | return *_ptr; |
223 | else |
224 | throw NullPointerException(); |
225 | } |
226 | |
227 | C* get() |
228 | { |
229 | return _ptr; |
230 | } |
231 | |
232 | const C* get() const |
233 | { |
234 | return _ptr; |
235 | } |
236 | |
237 | operator C* () |
238 | { |
239 | return _ptr; |
240 | } |
241 | |
242 | operator const C* () const |
243 | { |
244 | return _ptr; |
245 | } |
246 | |
247 | bool operator ! () const |
248 | { |
249 | return _ptr == 0; |
250 | } |
251 | |
252 | bool isNull() const |
253 | { |
254 | return _ptr == 0; |
255 | } |
256 | |
257 | C* duplicate() |
258 | { |
259 | if (_ptr) _ptr->duplicate(); |
260 | return _ptr; |
261 | } |
262 | |
263 | bool operator == (const AutoPtr& ptr) const |
264 | { |
265 | return _ptr == ptr._ptr; |
266 | } |
267 | |
268 | bool operator == (const C* ptr) const |
269 | { |
270 | return _ptr == ptr; |
271 | } |
272 | |
273 | bool operator == (C* ptr) const |
274 | { |
275 | return _ptr == ptr; |
276 | } |
277 | |
278 | bool operator != (const AutoPtr& ptr) const |
279 | { |
280 | return _ptr != ptr._ptr; |
281 | } |
282 | |
283 | bool operator != (const C* ptr) const |
284 | { |
285 | return _ptr != ptr; |
286 | } |
287 | |
288 | bool operator != (C* ptr) const |
289 | { |
290 | return _ptr != ptr; |
291 | } |
292 | |
293 | bool operator < (const AutoPtr& ptr) const |
294 | { |
295 | return _ptr < ptr._ptr; |
296 | } |
297 | |
298 | bool operator < (const C* ptr) const |
299 | { |
300 | return _ptr < ptr; |
301 | } |
302 | |
303 | bool operator < (C* ptr) const |
304 | { |
305 | return _ptr < ptr; |
306 | } |
307 | |
308 | bool operator <= (const AutoPtr& ptr) const |
309 | { |
310 | return _ptr <= ptr._ptr; |
311 | } |
312 | |
313 | bool operator <= (const C* ptr) const |
314 | { |
315 | return _ptr <= ptr; |
316 | } |
317 | |
318 | bool operator <= (C* ptr) const |
319 | { |
320 | return _ptr <= ptr; |
321 | } |
322 | |
323 | bool operator > (const AutoPtr& ptr) const |
324 | { |
325 | return _ptr > ptr._ptr; |
326 | } |
327 | |
328 | bool operator > (const C* ptr) const |
329 | { |
330 | return _ptr > ptr; |
331 | } |
332 | |
333 | bool operator > (C* ptr) const |
334 | { |
335 | return _ptr > ptr; |
336 | } |
337 | |
338 | bool operator >= (const AutoPtr& ptr) const |
339 | { |
340 | return _ptr >= ptr._ptr; |
341 | } |
342 | |
343 | bool operator >= (const C* ptr) const |
344 | { |
345 | return _ptr >= ptr; |
346 | } |
347 | |
348 | bool operator >= (C* ptr) const |
349 | { |
350 | return _ptr >= ptr; |
351 | } |
352 | |
353 | private: |
354 | C* _ptr; |
355 | }; |
356 | |
357 | |
358 | template <class C> |
359 | inline void swap(AutoPtr<C>& p1, AutoPtr<C>& p2) |
360 | { |
361 | p1.swap(p2); |
362 | } |
363 | |
364 | |
365 | } // namespace Poco |
366 | |
367 | |
368 | #endif // Foundation_AutoPtr_INCLUDED |
369 | |