1 | // |
2 | // RefPtr.h |
3 | // |
4 | // Library: Foundation |
5 | // Package: Core |
6 | // Module: RefPtr |
7 | // |
8 | // Definition of the RefPtr 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_RefPtr_INCLUDED |
18 | #define Foundation_RefPtr_INCLUDED |
19 | |
20 | |
21 | #include "Poco/Foundation.h" |
22 | #include "Poco/Exception.h" |
23 | |
24 | |
25 | namespace Poco { |
26 | |
27 | |
28 | template <class C> |
29 | class RefPtr |
30 | /// RefPtr is a "smart" pointer for classes implementing |
31 | /// reference counting based garbage collection. |
32 | /// To be usable with the RefPtr template, a class must |
33 | /// implement the following behaviour: |
34 | /// A class must maintain a reference count. |
35 | /// The constructors of the object initialize the reference |
36 | /// count to one. |
37 | /// The class must implement following public methods: |
38 | /// |
39 | /// void duplicate() |
40 | /// (increments the reference count by one) |
41 | /// |
42 | /// void release() |
43 | /// (decrements the reference count by one, if the reference |
44 | /// count reaches zero, deletes the object) |
45 | /// |
46 | /// For a conforming implementation, see RefCountedObject. |
47 | /// Unless there are specific reasons not to, it is recommended |
48 | /// that RefPtr-held objects inherit from RefCountedObject. |
49 | /// |
50 | /// RefPtr works in the following way: |
51 | /// If an RefPtr is assigned an ordinary pointer to |
52 | /// an object (via the constructor or the assignment operator), |
53 | /// it takes ownership of the object and the object's reference |
54 | /// count remains unchanged. |
55 | /// If the RefPtr is assigned another RefPtr, the |
56 | /// object's reference count is incremented by one by |
57 | /// calling duplicate() on its object. |
58 | /// The destructor of RefPtr calls release() on its |
59 | /// object. |
60 | /// RefPtr supports dereferencing with both the -> |
61 | /// and the * operator. An attempt to dereference a null |
62 | /// RefPtr results in a NullPointerException being thrown. |
63 | /// RefPtr also implements all relational operators. |
64 | /// Note that RefPtr allows casting of its encapsulated data types. |
65 | /// |
66 | /// RefPtr supports weak pointers to its internally held pointers. |
67 | /// For semantics, see WeakRefPtr documentation. |
68 | /// |
69 | { |
70 | public: |
71 | RefPtr(): _ptr(0) |
72 | { |
73 | } |
74 | |
75 | RefPtr(C* ptr): _ptr(ptr) |
76 | { |
77 | } |
78 | |
79 | RefPtr(C* ptr, bool shared): _ptr(ptr) |
80 | { |
81 | if (shared && _ptr) _ptr->duplicate(); |
82 | } |
83 | |
84 | RefPtr(const RefPtr& ptr): _ptr(ptr._ptr) |
85 | { |
86 | if (_ptr) _ptr->duplicate(); |
87 | } |
88 | |
89 | RefPtr(RefPtr&& ptr) : _ptr(ptr._ptr) |
90 | { |
91 | ptr._ptr = 0; |
92 | } |
93 | |
94 | template <class Other> |
95 | RefPtr(const RefPtr<Other>& ptr): _ptr(const_cast<Other*>(ptr.get())) |
96 | { |
97 | if (_ptr) _ptr->duplicate(); |
98 | } |
99 | |
100 | template <class Other> |
101 | RefPtr(RefPtr<Other>&& ptr): _ptr(ptr.get()) |
102 | { |
103 | ptr.resetMove(); |
104 | } |
105 | |
106 | ~RefPtr() |
107 | { |
108 | release(); |
109 | } |
110 | |
111 | RefPtr& assign(C* ptr) |
112 | { |
113 | if (_ptr != ptr) |
114 | { |
115 | release(); |
116 | _ptr = ptr; |
117 | } |
118 | return *this; |
119 | } |
120 | |
121 | RefPtr& assign(C* ptr, bool shared) |
122 | { |
123 | if (_ptr != ptr) |
124 | { |
125 | release(); |
126 | _ptr = ptr; |
127 | if (shared && _ptr) _ptr->duplicate(); |
128 | } |
129 | return *this; |
130 | } |
131 | |
132 | RefPtr& assign(const RefPtr& ptr) |
133 | { |
134 | if (&ptr != this) |
135 | { |
136 | release(); |
137 | _ptr = ptr._ptr; |
138 | if (_ptr) _ptr->duplicate(); |
139 | } |
140 | return *this; |
141 | } |
142 | |
143 | template <class Other> |
144 | RefPtr& assign(const RefPtr<Other>& ptr) |
145 | { |
146 | if (&ptr != (RefPtr<Other>*)this) |
147 | { |
148 | release(); |
149 | _ptr = const_cast<Other*>(ptr.get()); |
150 | if (_ptr) _ptr->duplicate(); |
151 | } |
152 | return *this; |
153 | } |
154 | |
155 | void resetMove() |
156 | { |
157 | if (_ptr) _ptr = 0; |
158 | } |
159 | |
160 | void reset() |
161 | { |
162 | if (_ptr) |
163 | { |
164 | release(); |
165 | _ptr = 0; |
166 | } |
167 | } |
168 | |
169 | void reset(C* ptr) |
170 | { |
171 | assign(ptr); |
172 | } |
173 | |
174 | void reset(C* ptr, bool shared) |
175 | { |
176 | assign(ptr, shared); |
177 | } |
178 | |
179 | void reset(const RefPtr& ptr) |
180 | { |
181 | assign(ptr); |
182 | } |
183 | |
184 | template <class Other> |
185 | void reset(const RefPtr<Other>& ptr) |
186 | { |
187 | assign<Other>(ptr); |
188 | } |
189 | |
190 | RefPtr& operator = (C* ptr) |
191 | { |
192 | return assign(ptr); |
193 | } |
194 | |
195 | RefPtr& operator = (const RefPtr& ptr) |
196 | { |
197 | return assign(ptr); |
198 | } |
199 | |
200 | template <class Other> |
201 | RefPtr& operator = (const RefPtr<Other>& ptr) |
202 | { |
203 | return assign<Other>(ptr); |
204 | } |
205 | |
206 | void moveAssign(C** pptr) |
207 | /// Move-assigns pointer to this RefPtr. |
208 | /// The pointer to pointer must not be null, |
209 | /// but the dereferenced pointer may be null. |
210 | /// Self move-assignment is no-op |
211 | { |
212 | poco_check_ptr (pptr); |
213 | |
214 | if (*pptr != _ptr) |
215 | { |
216 | reset(); |
217 | if (*pptr) |
218 | { |
219 | _ptr = *pptr; |
220 | *pptr = 0; |
221 | } |
222 | } |
223 | } |
224 | |
225 | RefPtr& operator = (RefPtr&& refPtr) |
226 | { |
227 | moveAssign(&refPtr._ptr); |
228 | return *this; |
229 | } |
230 | |
231 | template <class Other> |
232 | RefPtr& operator = (RefPtr<Other>&& otherRefPtr) |
233 | { |
234 | Other* pOther = otherRefPtr.get(); |
235 | if (pOther != _ptr) |
236 | { |
237 | reset(); |
238 | if (pOther) |
239 | { |
240 | _ptr = pOther; |
241 | otherRefPtr.resetMove(); |
242 | } |
243 | } |
244 | return *this; |
245 | } |
246 | |
247 | void swap(RefPtr& ptr) |
248 | { |
249 | std::swap(_ptr, ptr._ptr); |
250 | } |
251 | |
252 | template <class Other> |
253 | RefPtr<Other> cast() const |
254 | /// Casts the RefPtr via a dynamic cast to the given type. |
255 | /// Returns an RefPtr containing NULL if the cast fails. |
256 | /// Example: (assume class Sub: public Super) |
257 | /// RefPtr<Super> super(new Sub()); |
258 | /// RefPtr<Sub> sub = super.cast<Sub>(); |
259 | /// poco_assert (sub.get()); |
260 | { |
261 | return RefPtr<Other>(dynamic_cast<Other*>(_ptr), true); |
262 | } |
263 | |
264 | template <class Other> |
265 | RefPtr<Other> unsafeCast() const |
266 | /// Casts the RefPtr via a static cast to the given type. |
267 | /// Example: (assume class Sub: public Super) |
268 | /// RefPtr<Super> super(new Sub()); |
269 | /// RefPtr<Sub> sub = super.unsafeCast<Sub>(); |
270 | /// poco_assert (sub.get()); |
271 | { |
272 | return RefPtr<Other>(static_cast<Other*>(_ptr), true); |
273 | } |
274 | |
275 | C* operator -> () |
276 | { |
277 | if (_ptr) |
278 | return _ptr; |
279 | else |
280 | throw NullPointerException(); |
281 | } |
282 | |
283 | const C* operator -> () const |
284 | { |
285 | if (_ptr) |
286 | return _ptr; |
287 | else |
288 | throw NullPointerException(); |
289 | } |
290 | |
291 | C& operator * () |
292 | { |
293 | if (_ptr) |
294 | return *_ptr; |
295 | else |
296 | throw NullPointerException(); |
297 | } |
298 | |
299 | const C& operator * () const |
300 | { |
301 | if (_ptr) |
302 | return *_ptr; |
303 | else |
304 | throw NullPointerException(); |
305 | } |
306 | |
307 | C* get() |
308 | { |
309 | return _ptr; |
310 | } |
311 | |
312 | const C* get() const |
313 | { |
314 | return _ptr; |
315 | } |
316 | |
317 | operator C* () |
318 | { |
319 | return _ptr; |
320 | } |
321 | |
322 | operator const C* () const |
323 | { |
324 | return _ptr; |
325 | } |
326 | |
327 | bool operator ! () const |
328 | { |
329 | return _ptr == 0; |
330 | } |
331 | |
332 | bool isNull() const |
333 | { |
334 | return _ptr == 0; |
335 | } |
336 | |
337 | C* duplicate() |
338 | { |
339 | if (_ptr) _ptr->duplicate(); |
340 | return _ptr; |
341 | } |
342 | |
343 | bool operator == (const RefPtr& ptr) const |
344 | { |
345 | return _ptr == ptr._ptr; |
346 | } |
347 | |
348 | bool operator == (const C* ptr) const |
349 | { |
350 | return _ptr == ptr; |
351 | } |
352 | |
353 | bool operator == (C* ptr) const |
354 | { |
355 | return _ptr == ptr; |
356 | } |
357 | |
358 | bool operator != (const RefPtr& ptr) const |
359 | { |
360 | return _ptr != ptr._ptr; |
361 | } |
362 | |
363 | bool operator != (const C* ptr) const |
364 | { |
365 | return _ptr != ptr; |
366 | } |
367 | |
368 | bool operator != (C* ptr) const |
369 | { |
370 | return _ptr != ptr; |
371 | } |
372 | |
373 | bool operator < (const RefPtr& ptr) const |
374 | { |
375 | return _ptr < ptr._ptr; |
376 | } |
377 | |
378 | bool operator < (const C* ptr) const |
379 | { |
380 | return _ptr < ptr; |
381 | } |
382 | |
383 | bool operator < (C* ptr) const |
384 | { |
385 | return _ptr < ptr; |
386 | } |
387 | |
388 | bool operator <= (const RefPtr& ptr) const |
389 | { |
390 | return _ptr <= ptr._ptr; |
391 | } |
392 | |
393 | bool operator <= (const C* ptr) const |
394 | { |
395 | return _ptr <= ptr; |
396 | } |
397 | |
398 | bool operator <= (C* ptr) const |
399 | { |
400 | return _ptr <= ptr; |
401 | } |
402 | |
403 | bool operator > (const RefPtr& ptr) const |
404 | { |
405 | return _ptr > ptr._ptr; |
406 | } |
407 | |
408 | bool operator > (const C* ptr) const |
409 | { |
410 | return _ptr > ptr; |
411 | } |
412 | |
413 | bool operator > (C* ptr) const |
414 | { |
415 | return _ptr > ptr; |
416 | } |
417 | |
418 | bool operator >= (const RefPtr& ptr) const |
419 | { |
420 | return _ptr >= ptr._ptr; |
421 | } |
422 | |
423 | bool operator >= (const C* ptr) const |
424 | { |
425 | return _ptr >= ptr; |
426 | } |
427 | |
428 | bool operator >= (C* ptr) const |
429 | { |
430 | return _ptr >= ptr; |
431 | } |
432 | |
433 | private: |
434 | void release() |
435 | { |
436 | if (_ptr) _ptr->release(); |
437 | } |
438 | |
439 | C* _ptr = 0; |
440 | }; |
441 | |
442 | |
443 | template <class C> |
444 | inline void swap(RefPtr<C>& p1, RefPtr<C>& p2) |
445 | { |
446 | p1.swap(p2); |
447 | } |
448 | |
449 | |
450 | } // namespace Poco |
451 | |
452 | |
453 | #endif // Foundation_RefPtr_INCLUDED |
454 | |