1//
2// WeakRefPtr.h
3//
4// Library: Foundation
5// Package: Core
6// Module: WeakRefPtr
7//
8// Definition of the WeakRefPtr 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_WeakRefPtr_INCLUDED
18#define Foundation_WeakRefPtr_INCLUDED
19
20
21#include "Poco/Foundation.h"
22#include "Poco/RefCountedObject.h"
23#include "Poco/Exception.h"
24
25
26namespace Poco {
27
28
29template <class C>
30class WeakRefPtr
31 /// WeakRefPtr is a "smart" pointer for classes implementing mixed
32 /// ("strong"/"weak") reference counting. WeakRefPtr keeps a "weak"
33 /// reference to the object; the referenced object lifetime is not
34 /// dependent on the WeakRefPtr reference(s) to it - it will be
35 /// destroyed when the last strong reference count reaches zero,
36 /// even if weak references still exist.
37 /// The main purpose for WeakRefPtr is to avoid RefPtr circular
38 /// reference problem (ie. memory leaks).
39 /// To enforce referenced object's lifetime duration for as long as
40 /// references to it exist, use RefPtr. A RefPtr of the underlying
41 /// pointer can be obtained from WeakRefPtr by calling lock().
42{
43public:
44 WeakRefPtr(): _ptr(0)
45 /// Creates null WeakRefPtr
46 {
47 }
48
49 WeakRefPtr(const WeakRefPtr& weakPtr): _ptr(weakPtr._ptr),
50 _pCounter(weakPtr._pCounter)
51 /// Creates WeakRefPtr by copying from another WeakRefPtr
52 /// and increasing weak count.
53 {
54 duplicate();
55 }
56
57 WeakRefPtr(WeakRefPtr&& weakPtr): _ptr(weakPtr._ptr),
58 _pCounter(weakPtr._pCounter)
59 /// Creates WeakRefPtr by moving from another WeakRefPtr.
60 {
61 weakPtr._ptr = 0;
62 weakPtr._pCounter = 0;
63 }
64
65 template <class Other>
66 WeakRefPtr(const WeakRefPtr<Other>& weakPtr): _ptr(const_cast<Other*>(weakPtr._ptr)),
67 _pCounter(weakPtr._pCounter)
68 /// Creates WeakRefPtr by copying from another WeakRefPtr of different
69 /// type. Pointer held by another WeakRefPtr must be convertible to pointer
70 /// held by this WeakRefPtr.
71 {
72 duplicate();
73 }
74
75 template <class Other>
76 WeakRefPtr(WeakRefPtr<Other>&& weakPtr): _ptr(weakPtr._ptr),
77 _pCounter(weakPtr._pCounter)
78 /// Creates WeakRefPtr by moving from another WeakRefPtr.
79 /// Pointer held by another WeakRefPtr must be convertible to
80 /// pointer held by this WeakRefPtr.
81 {
82 weakPtr._ptr = 0;
83 weakPtr._pCounter = 0;
84 }
85
86 WeakRefPtr(const RefPtr<C>& autoPtr): _ptr(const_cast<RefPtr<C>&>(autoPtr).get()),
87 _pCounter(_ptr ? _ptr->counter() : 0)
88 /// Creates WeakRefPtr by copying from a RefPtr and
89 /// increasing the weak count.
90 {
91 duplicate();
92 }
93
94 template <class Other>
95 WeakRefPtr(const RefPtr<Other>& autoPtr): _ptr(const_cast<RefPtr<C>&>(autoPtr).get()),
96 _pCounter(_ptr ? _ptr->counter() : 0)
97 /// Creates WeakRefPtr by copying from a RefPtr of different
98 /// type and increasing the weak count. Pointer held by the RefPtr
99 /// must be convertible to pointer held by this WeakRefPtr.
100 {
101 duplicate();
102 }
103
104 WeakRefPtr(RefPtr<C>&& autoPtr): _ptr(autoPtr.get()),
105 _pCounter(_ptr ? _ptr->counter() : 0)
106 /// Creates WeakRefPtr by moving from a RefPtr and
107 /// increasing the weak count.
108 ///
109 /// Moved-from RefPtr count is decreased and the
110 /// pointer is set to zero.
111 {
112 duplicate();
113 autoPtr.reset();
114 }
115
116 template <class Other>
117 WeakRefPtr(RefPtr<Other>&& autoPtr): _ptr(autoPtr.get()),
118 _pCounter(_ptr ? _ptr->counter() : 0)
119 /// Creates WeakRefPtr by moving from a RefPtr of different
120 /// type. Pointer held by the RefPtr must be convertible to
121 /// pointer held by this WeakRefPtr.
122 ///
123 /// Moved-from RefPtr count is decreased and the
124 /// pointer is set to zero.
125 {
126 duplicate();
127 autoPtr.reset();
128 }
129
130 ~WeakRefPtr()
131 /// Releases the weak count and destroys the WeakRefPtr.
132 {
133 release();
134 }
135
136 WeakRefPtr& operator = (const WeakRefPtr<C>& weakPtr)
137 /// Assigns WeakRefPtr to this WeakRefPtr by copying
138 /// from another WeakRefPtr, releases the weak count
139 /// to previously held pointer and increases the
140 /// weak count to the newly held one.
141 {
142 if (&weakPtr != this)
143 {
144 release();
145 _ptr = const_cast<C*>(weakPtr.get());
146 _pCounter = _ptr ? _ptr->counter() : 0;
147 duplicate();
148 }
149 return *this;
150 }
151
152 WeakRefPtr& operator = (WeakRefPtr<C>&& weakPtr)
153 /// Assigns WeakRefPtr to this WeakRefPtr by moving
154 /// from another WeakRefPtr, releases the weak count
155 /// to previously held pointer and increases the
156 /// weak count to the newly held one.
157 {
158 if (&weakPtr != this)
159 {
160 release();
161 _ptr = const_cast<C*>(weakPtr.get());
162 _pCounter = _ptr ? _ptr->counter() : 0;
163 duplicate();
164 weakPtr._ptr = 0;
165 weakPtr._pCounter = 0;
166 }
167 return *this;
168 }
169
170 template <class Other>
171 WeakRefPtr& operator = (const WeakRefPtr<Other>& weakPtr)
172 /// Assigns WeakRefPtr to this WeakRefPtr by copying from
173 /// another WeakRefPtr of different type, releases the weak
174 /// count to previously held pointer and increases the
175 /// weak count to the newly held one.
176 /// Pointer to the type held by the RefPtr must be
177 /// convertible to pointer to the type held by this
178 /// WeakRefPtr.
179 {
180 if (&weakPtr != this)
181 {
182 release();
183 _ptr = const_cast<Other*>(weakPtr.get());
184 _pCounter = _ptr ? _ptr->counter() : 0;
185 duplicate();
186 }
187 return *this;
188 }
189
190 template <class Other>
191 WeakRefPtr& operator = (WeakRefPtr<Other>&& weakPtr)
192 /// Assigns WeakRefPtr to this WeakRefPtr by moving from
193 /// another WeakRefPtr of different type, releases the weak
194 /// count to previously held pointer and increases the
195 /// weak count to the newly held one.
196 /// Pointer to the type held by the RefPtr must be
197 /// convertible to pointer to the type held by this
198 /// WeakRefPtr.
199 {
200 if (&weakPtr != this)
201 {
202 release();
203 _ptr = const_cast<Other*>(weakPtr.get());
204 _pCounter = _ptr ? _ptr->counter() : 0;
205 weakPtr._ptr = 0;
206 weakPtr._pCounter = 0;
207 duplicate();
208 }
209 return *this;
210 }
211
212 WeakRefPtr& operator = (const RefPtr<C>& autoPtr)
213 /// Assigns RefPtr to this WeakRefPtr by copying from
214 /// another RefPtr, releases the weak count to
215 /// previously held pointer and increases the weak
216 /// count to the newly held one.
217 {
218 if (autoPtr.get() != _ptr)
219 {
220 release();
221 _ptr = const_cast<C*>(autoPtr.get());
222 _pCounter = _ptr ? _ptr->counter() : 0;
223 duplicate();
224 }
225 return *this;
226 }
227
228 WeakRefPtr& operator = (RefPtr<C>&& autoPtr)
229 /// Assigns RefPtr to this WeakRefPtr by moving from
230 /// another RefPtr, releases the weak count to
231 /// previously held pointer and increases the weak
232 /// count to the newly held one.
233 ///
234 /// Moved-from RefPtr count is decreased and the
235 /// pointer is set to zero.
236 {
237 if (autoPtr.get() != _ptr)
238 {
239 release();
240 _ptr = const_cast<C*>(autoPtr.get());
241 _pCounter = _ptr ? _ptr->counter() : 0;
242 autoPtr.reset();
243 duplicate();
244 }
245 return *this;
246 }
247
248 template <class Other>
249 WeakRefPtr& operator = (const RefPtr<Other>& autoPtr)
250 /// Assigns RefPtr to this WeakRefPtr by copying from
251 /// another RefPtr of different type, releases the weak
252 /// count to previously held pointer and increases the
253 /// weak count to the newly held one.
254 /// Pointer to the type held by the RefPtr must be
255 /// convertible to pointer to the type held by this
256 /// WeakRefPtr.
257 {
258 if (autoPtr.get() != _ptr)
259 {
260 release();
261 _ptr = const_cast<Other*>(autoPtr.get());
262 _pCounter = _ptr ? _ptr->counter() : 0;
263 duplicate();
264 }
265 return *this;
266 }
267
268 template <class Other>
269 WeakRefPtr& operator = (RefPtr<Other>&& autoPtr)
270 /// Assigns RefPtr to this WeakRefPtr by moving from
271 /// another RefPtr of different type, releases the weak
272 /// count to previously held pointer and increases the
273 /// weak count to the newly held one.
274 /// Pointer to the type held by the RefPtr must be
275 /// convertible to pointer to the type held by this
276 /// WeakRefPtr.
277 ///
278 /// Moved-from RefPtr count is decreased and the
279 /// pointer is set to zero.
280 {
281 if (autoPtr.get() != _ptr)
282 {
283 release();
284 _ptr = const_cast<Other*>(autoPtr.get());
285 _pCounter = _ptr ? _ptr->counter() : 0;
286 autoPtr.reset();
287 duplicate();
288 }
289 return *this;
290 }
291
292 C* operator -> ()
293 {
294 if (good()) return _ptr;
295 throw InvalidAccessException("WeakRefPtr::operator -> ()");
296 }
297
298 const C* operator -> () const
299 {
300 if (good()) return _ptr;
301 throw InvalidAccessException("WeakRefPtr::operator -> () const");
302 }
303
304 C& operator * ()
305 {
306 if (good()) return *_ptr;
307 throw InvalidAccessException("WeakRefPtr::operator * ()");
308 }
309
310 const C& operator * () const
311 {
312 if (good()) return *_ptr;
313 throw InvalidAccessException("WeakRefPtr::operator * () const");
314 }
315
316 C* get()
317 {
318 if (good()) return _ptr;
319 return 0;
320 }
321
322 const C* get() const
323 {
324 if (good()) return _ptr;
325 return 0;
326 }
327
328 operator bool () const
329 {
330 return good();
331 }
332
333 operator RefPtr<C> () const
334 {
335 return lock();
336 }
337
338 template <typename Other>
339 operator RefPtr<Other> () const
340 {
341 return lock().template cast<Other>();
342 }
343
344 bool operator ! () const
345 {
346 if (good()) return _ptr == 0;
347 return false;
348 }
349
350 bool isNull() const
351 {
352 if (good()) return (_pCounter == 0 || _ptr == 0);
353 return true;
354 }
355
356 bool operator == (const WeakRefPtr& ptr) const
357 {
358 if (good()) return _ptr == ptr;
359 else if (isNull() && !ptr) return true;
360 return false;
361 }
362
363 bool operator == (const RefPtr<C>& ptr) const
364 {
365 if (good()) return _ptr == ptr;
366 else if (isNull() && !ptr) return true;
367 return false;
368 }
369
370 bool operator == (const C* ptr) const
371 {
372 if (good()) return _ptr == ptr;
373 else if (isNull() && !ptr) return true;
374 return false;
375 }
376
377 bool operator == (C* ptr) const
378 {
379 if (good()) return _ptr == ptr;
380 else if (isNull() && !ptr) return true;
381 return false;
382 }
383
384 bool operator != (const WeakRefPtr& ptr) const
385 {
386 if (good()) return _ptr != ptr;
387 else if (isNull() && !ptr) return false;
388 return true;
389 }
390
391 bool operator != (const RefPtr<C>& ptr) const
392 {
393 if (good()) return _ptr != ptr;
394 else if (isNull() && !ptr) return false;
395 return true;
396 }
397
398 bool operator != (const C* ptr) const
399 {
400 if (good()) return _ptr != ptr;
401 else if (isNull() && !ptr) return false;
402 return true;
403 }
404
405 bool operator != (C* ptr) const
406 {
407 if (good()) return _ptr != ptr;
408 else if (isNull() && !ptr) return false;
409 return true;
410 }
411
412 int referenceCount()
413 /// Returns the strong reference count.
414 {
415 return good() ? _pCounter->count() : 0;
416 }
417
418 RefPtr<C> lock() const
419 /// Returns a RefPtr. If all the strong references
420 /// have expired, the returned RefPtr wi be null.
421 {
422 good(); // to set _ptr to 0, if needed
423 return RefPtr<C>(_ptr, true);
424 }
425
426 void duplicate()
427 /// Increments the weak reference count.
428 {
429 if (_pCounter) _pCounter = _pCounter->duplicateWeak();
430 if (!_pCounter) _ptr = 0;
431 }
432
433 void release()
434 /// Decrements the weak reference count.
435 {
436 if (_pCounter) _pCounter = _pCounter->releaseWeak();
437 if (!_pCounter) _ptr = 0;
438 }
439
440private:
441
442 bool good() const
443 {
444 _ptr = _pCounter ? ((_pCounter->count() > 0) ? _ptr : 0) : 0;
445 return _ptr != 0;
446 }
447
448 typedef WeakRefCounter CounterType;
449
450 mutable C* _ptr = 0;
451 CounterType* _pCounter = 0;
452};
453
454
455} // namespace Poco
456
457
458#endif // Foundation_WeakRefPtr_INCLUDED
459