1//
2// SharedPtr.h
3//
4// Library: Foundation
5// Package: Core
6// Module: SharedPtr
7//
8// Definition of the SharedPtr template class.
9//
10// Copyright (c) 2005-2008, Applied Informatics Software Engineering GmbH.
11// and Contributors.
12//
13// SPDX-License-Identifier: BSL-1.0
14//
15
16
17#ifndef Foundation_SharedPtr_INCLUDED
18#define Foundation_SharedPtr_INCLUDED
19
20
21#include "Poco/Foundation.h"
22#include "Poco/Exception.h"
23#include "Poco/AtomicCounter.h"
24#include <algorithm>
25
26
27namespace Poco {
28
29
30class ReferenceCounter
31 /// Simple ReferenceCounter object, does not delete itself when count reaches 0.
32{
33public:
34 ReferenceCounter(): _cnt(1)
35 {
36 }
37
38 void duplicate()
39 {
40 ++_cnt;
41 }
42
43 int release()
44 {
45 return --_cnt;
46 }
47
48 int referenceCount() const
49 {
50 return _cnt.value();
51 }
52
53private:
54 AtomicCounter _cnt;
55};
56
57
58template <class C>
59class ReleasePolicy
60 /// The default release policy for SharedPtr, which
61 /// simply uses the delete operator to delete an object.
62{
63public:
64 static void release(C* pObj)
65 /// Delete the object.
66 /// Note that pObj can be 0.
67 {
68 delete pObj;
69 }
70};
71
72
73template <class C>
74class ReleaseArrayPolicy
75 /// The release policy for SharedPtr holding arrays.
76{
77public:
78 static void release(C* pObj)
79 /// Delete the object.
80 /// Note that pObj can be 0.
81 {
82 delete [] pObj;
83 }
84};
85
86
87template <class C, class RC = ReferenceCounter, class RP = ReleasePolicy<C> >
88class SharedPtr
89 /// SharedPtr is a "smart" pointer for classes implementing
90 /// reference counting based garbage collection.
91 /// SharedPtr is thus similar to AutoPtr. Unlike the
92 /// AutoPtr template, which can only be used with
93 /// classes that support reference counting, SharedPtr
94 /// can be used with any class. For this to work, a
95 /// SharedPtr manages a reference count for the object
96 /// it manages.
97 ///
98 /// SharedPtr works in the following way:
99 /// If an SharedPtr is assigned an ordinary pointer to
100 /// an object (via the constructor or the assignment operator),
101 /// it takes ownership of the object and the object's reference
102 /// count is initialized to one.
103 /// If the SharedPtr is assigned another SharedPtr, the
104 /// object's reference count is incremented by one.
105 /// The destructor of SharedPtr decrements the object's
106 /// reference count by one and deletes the object if the
107 /// reference count reaches zero.
108 /// SharedPtr supports dereferencing with both the ->
109 /// and the * operator. An attempt to dereference a null
110 /// SharedPtr results in a NullPointerException being thrown.
111 /// SharedPtr also implements all relational operators and
112 /// a cast operator in case dynamic casting of the encapsulated data types
113 /// is required.
114{
115public:
116 SharedPtr(): _pCounter(new RC), _ptr(0)
117 {
118 }
119
120 SharedPtr(C* ptr)
121 try:
122 _pCounter(new RC),
123 _ptr(ptr)
124 {
125 }
126 catch (...)
127 {
128 RP::release(ptr);
129 }
130
131 template <class Other, class OtherRP>
132 SharedPtr(const SharedPtr<Other, RC, OtherRP>& ptr): _pCounter(ptr._pCounter), _ptr(const_cast<Other*>(ptr.get()))
133 {
134 _pCounter->duplicate();
135 }
136
137 SharedPtr(const SharedPtr& ptr): _pCounter(ptr._pCounter), _ptr(ptr._ptr)
138 {
139 _pCounter->duplicate();
140 }
141
142 ~SharedPtr()
143 {
144 try
145 {
146 release();
147 }
148 catch (...)
149 {
150 poco_unexpected();
151 }
152 }
153
154 SharedPtr& assign(C* ptr)
155 {
156 if (get() != ptr)
157 {
158 SharedPtr tmp(ptr);
159 swap(tmp);
160 }
161 return *this;
162 }
163
164 SharedPtr& assign(const SharedPtr& ptr)
165 {
166 if (&ptr != this)
167 {
168 SharedPtr tmp(ptr);
169 swap(tmp);
170 }
171 return *this;
172 }
173
174 template <class Other, class OtherRP>
175 SharedPtr& assign(const SharedPtr<Other, RC, OtherRP>& ptr)
176 {
177 if (ptr.get() != _ptr)
178 {
179 SharedPtr tmp(ptr);
180 swap(tmp);
181 }
182 return *this;
183 }
184
185 SharedPtr& operator = (C* ptr)
186 {
187 return assign(ptr);
188 }
189
190 SharedPtr& operator = (const SharedPtr& ptr)
191 {
192 return assign(ptr);
193 }
194
195 template <class Other, class OtherRP>
196 SharedPtr& operator = (const SharedPtr<Other, RC, OtherRP>& ptr)
197 {
198 return assign<Other>(ptr);
199 }
200
201 void swap(SharedPtr& ptr)
202 {
203 std::swap(_ptr, ptr._ptr);
204 std::swap(_pCounter, ptr._pCounter);
205 }
206
207 template <class Other>
208 SharedPtr<Other, RC, RP> cast() const
209 /// Casts the SharedPtr via a dynamic cast to the given type.
210 /// Returns an SharedPtr containing NULL if the cast fails.
211 /// Example: (assume class Sub: public Super)
212 /// SharedPtr<Super> super(new Sub());
213 /// SharedPtr<Sub> sub = super.cast<Sub>();
214 /// poco_assert (sub.get());
215 {
216 Other* pOther = dynamic_cast<Other*>(_ptr);
217 if (pOther)
218 return SharedPtr<Other, RC, RP>(_pCounter, pOther);
219 return SharedPtr<Other, RC, RP>();
220 }
221
222 template <class Other>
223 SharedPtr<Other, RC, RP> unsafeCast() const
224 /// Casts the SharedPtr via a static cast to the given type.
225 /// Example: (assume class Sub: public Super)
226 /// SharedPtr<Super> super(new Sub());
227 /// SharedPtr<Sub> sub = super.unsafeCast<Sub>();
228 /// poco_assert (sub.get());
229 {
230 Other* pOther = static_cast<Other*>(_ptr);
231 return SharedPtr<Other, RC, RP>(_pCounter, pOther);
232 }
233
234 C* operator -> ()
235 {
236 return deref();
237 }
238
239 const C* operator -> () const
240 {
241 return deref();
242 }
243
244 C& operator * ()
245 {
246 return *deref();
247 }
248
249 const C& operator * () const
250 {
251 return *deref();
252 }
253
254 C* get()
255 {
256 return _ptr;
257 }
258
259 const C* get() const
260 {
261 return _ptr;
262 }
263
264 operator C* ()
265 {
266 return _ptr;
267 }
268
269 operator const C* () const
270 {
271 return _ptr;
272 }
273
274 bool operator ! () const
275 {
276 return _ptr == 0;
277 }
278
279 bool isNull() const
280 {
281 return _ptr == 0;
282 }
283
284 bool operator == (const SharedPtr& ptr) const
285 {
286 return get() == ptr.get();
287 }
288
289 bool operator == (const C* ptr) const
290 {
291 return get() == ptr;
292 }
293
294 bool operator == (C* ptr) const
295 {
296 return get() == ptr;
297 }
298
299 bool operator != (const SharedPtr& ptr) const
300 {
301 return get() != ptr.get();
302 }
303
304 bool operator != (const C* ptr) const
305 {
306 return get() != ptr;
307 }
308
309 bool operator != (C* ptr) const
310 {
311 return get() != ptr;
312 }
313
314 bool operator < (const SharedPtr& ptr) const
315 {
316 return get() < ptr.get();
317 }
318
319 bool operator < (const C* ptr) const
320 {
321 return get() < ptr;
322 }
323
324 bool operator < (C* ptr) const
325 {
326 return get() < ptr;
327 }
328
329 bool operator <= (const SharedPtr& ptr) const
330 {
331 return get() <= ptr.get();
332 }
333
334 bool operator <= (const C* ptr) const
335 {
336 return get() <= ptr;
337 }
338
339 bool operator <= (C* ptr) const
340 {
341 return get() <= ptr;
342 }
343
344 bool operator > (const SharedPtr& ptr) const
345 {
346 return get() > ptr.get();
347 }
348
349 bool operator > (const C* ptr) const
350 {
351 return get() > ptr;
352 }
353
354 bool operator > (C* ptr) const
355 {
356 return get() > ptr;
357 }
358
359 bool operator >= (const SharedPtr& ptr) const
360 {
361 return get() >= ptr.get();
362 }
363
364 bool operator >= (const C* ptr) const
365 {
366 return get() >= ptr;
367 }
368
369 bool operator >= (C* ptr) const
370 {
371 return get() >= ptr;
372 }
373
374 int referenceCount() const
375 {
376 return _pCounter->referenceCount();
377 }
378
379protected:
380 C* deref() const
381 {
382 if (!_ptr)
383 throw NullPointerException();
384
385 return _ptr;
386 }
387
388 void release()
389 {
390 poco_assert_dbg (_pCounter);
391 int i = _pCounter->release();
392 if (i == 0)
393 {
394 RP::release(_ptr);
395 _ptr = 0;
396
397 delete _pCounter;
398 _pCounter = 0;
399 }
400 }
401
402 SharedPtr(RC* pCounter, C* ptr): _pCounter(pCounter), _ptr(ptr)
403 /// for cast operation
404 {
405 poco_assert_dbg (_pCounter);
406 _pCounter->duplicate();
407 }
408
409protected:
410 RC* _pCounter;
411 C* _ptr;
412
413 template <class OtherC, class OtherRC, class OtherRP> friend class SharedPtr;
414};
415
416
417template <class C, class RC, class RP>
418inline void swap(SharedPtr<C, RC, RP>& p1, SharedPtr<C, RC, RP>& p2)
419{
420 p1.swap(p2);
421}
422
423
424} // namespace Poco
425
426
427#endif // Foundation_SharedPtr_INCLUDED
428