1 /***************************************************************************
2 begin : Wed Jan 1 17:56 CET 2003
3 copyright : (C) 2003 by Tim Jansen
5 ***************************************************************************/
7 /***************************************************************************
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
14 ***************************************************************************/
26 struct SmartPtrRefCount
{
27 SmartPtrRefCount(int toObj
, int toThis
) :
31 int refsToObject
; // number of pointers to the object, 0 if released
32 int refsToThis
; // number of pointer to the ref count
36 * SmartPtr is a reference counting smart pointer. When you create
37 * the first instance it will create a new counter for the pointee
38 * and it share it with all other SmartPtr instances for that pointee.
39 * The reference count can only be kept accurate when you do not create
40 * a second 'realm' of references by converting a SmartPtr into a
41 * regular pointer and then create a new SmartPtr from that pointer.
42 * When the last instance of a SmartPtr for the given object has been
43 * deleted the object itself will be deleted. You can stop the SmartPtr
44 * system to manage an object by calling @ref release() on any of
45 * the pointers pointing to that object. All SmartPtrs will then stop
46 * managing the object, and you can also safely create a second 'realm'.
48 * SmartPtr can be combined with @ref WeakPtr. A WeakPtr
49 * does not influence its life cycle, but notices when a SmartPtr
52 * The recommended way to use SmartPtr and @ref WeakPtr is to use SmartPtr
53 * for all aggregations and WeakPtr for associations. Unlike auto_ptr,
54 * SmartPtr can be used in collections.
56 * SmartPtr is not thread-safe. All instances of SmartPtrs pointing
57 * to a pointee must always be in the same thread, unless you break
58 * the 'realm' by calling @ref release() in one thread and give the
59 * original pointer the other thread. It can then create a new SmartPtr
60 * and control the lifecycle of the object.
66 public: // members are public because of problems with gcc 3.2
72 mutable SmartPtrRefCount
*rc
; // if !rc, refcount=1 is assumed
81 if (rc
->refsToObject
> 0) {
82 Q_ASSERT(rc
->refsToObject
>= rc
->refsToThis
);
83 if (rc
->refsToObject
== 1) {
85 rc
->refsToObject
= -1;
91 if (rc
->refsToThis
< 1)
96 void init(T
*sptr
, SmartPtrRefCount
*&orc
)
102 orc
= new SmartPtrRefCount(2, 2);
108 if (rc
->refsToObject
) {
109 // prevent initialization from invalid WeakPtr
110 Q_ASSERT(rc
->refsToObject
> 0);
116 SmartPtr(T
*p
, SmartPtrRefCount
*&orc
)
123 * Creates a SmartPtr that refers to the given pointer @p.
124 * SmartPtr will take control over the object and delete it
125 * when the last SmartPtr that referes to the object
127 * @param p the pointer to the object to manage, or the null pointer
136 * Copies the given SmartPtr, sharing ownership with the other
137 * pointer. Increases the reference count by 1 (if the object
138 * has not been @ref release()d).
139 * @param sptr the object pointer to copy
141 SmartPtr(const SmartPtr
<T
> &sptr
)
143 init(sptr
.ptr
, sptr
.rc
);
147 * Copies the given SmartPtr, sharing ownership with the other
148 * pointer. Increases the reference count by 1 (if the object
149 * has not been @ref release()d).
150 * @param sptr the object pointer to copy
153 SmartPtr(const SmartPtr
<T2
> &sptr
)
155 init((T
*)sptr
.ptr
, sptr
.rc
);
159 * Delete the pointer and, if the reference count is one and the object has not
160 * been released, deletes the object.
167 * Copies the given SmartPtr, sharing ownership with the other
168 * pointer. Increases the reference count by 1 (if the object
169 * has not been @ref release()d). The original object will be dereferenced
170 * and thus deleted, if the reference count is 1.
171 * @param sptr the object pointer to copy
172 * @return this SmartPtr object
174 SmartPtr
&operator=(const SmartPtr
<T
> &sptr
) {
179 init(sptr
.ptr
, sptr
.rc
);
184 * Copies the given SmartPtr, sharing ownership with the other
185 * pointer. Increases the reference count by 1 (if the object
186 * has not been @ref release()d). The original object will be dereferenced
187 * and thus deleted, if the reference count is 1.
188 * @param sptr the object pointer to copy
189 * @return this SmartPtr object
192 SmartPtr
&operator=(const SmartPtr
<T2
> &sptr
) {
193 if (this == static_cast<SmartPtr
<T
> >(&sptr
))
197 init(static_cast<T
>(sptr
.ptr
), sptr
.rc
);
202 * Sets the SmartPointer to the given value. The original object
203 * will be dereferenced and thus deleted, if the reference count is 1.
204 * @param p the value of the new pointer
216 * Releases the ptr. This means it will not be memory-managed
217 * anymore, neither by this SmartPtr nor by any other pointer that
218 * shares the object. The caller is responsible for freeing the
219 * object. It is possible to assign the plain pointer (but not the
220 * SmartPtr!) to another SmartPtr that will then start memory
221 * management. This may be useful, for example, to let another
222 * thread manage the lifecyle.
223 * @return the pointer, must be freed by the user
228 rc
= new SmartPtrRefCount(0, 1);
230 rc
->refsToObject
= 0;
235 * Sets the SmartPointer to the given value. The original object
236 * will be dereferenced and thus deleted, if the reference count is 1.
237 * @param p the value of the new pointer
238 * @return this SmartPtr object
240 SmartPtr
&operator=(T
*p
) {
246 * Returns true if the SmartPtr points to an actual object, false
247 * if it is the null pointer.
248 * @return true for an actual pointer, false for the null pointer
250 operator bool() const {
255 * Returns the plain pointer to the pointed object. The object will
256 * still be managed by the SmartPtr. You must ensure that the pointer
257 * is valid (so don't delete the SmartPtr before you are done with the
259 * @return the plain pointer
265 operator T2
*() const {
266 return static_cast<T2
*>(ptr
);
270 * Returns the plain pointer to the pointed object. The object will
271 * still be managed by the SmartPtr. You must ensure that the pointer
272 * is valid (so don't delete the SmartPtr before you are done with the
274 * @return the plain pointer
280 operator const T2
*() const {
281 return static_cast<const T2
*>(ptr
);
285 * Returns a reference to the pointed object. This works exactly
286 * like on a regular pointer.
287 * @return the pointer object
294 * Returns a reference to the pointed object. This works exactly
295 * like on a regular pointer.
296 * @return the pointer object
298 const T
& operator*() const {
303 * Access a member of the pointed object. This works exactly
304 * like on a regular pointer.
305 * @return the pointer
312 * Access a member of the pointed object. This works exactly
313 * like on a regular pointer.
314 * @return the pointer
316 const T
* operator->() const {
321 * Compares two SmartPtrs. They are equal if both point to the
323 * @return true if both point to the same object
325 bool operator==(const SmartPtr
<T
>& sptr
) const {
326 return ptr
== sptr
.ptr
;
330 * Compares two SmartPtrs. They are unequal if both point to
332 * @return true if both point to different objects
334 bool operator!=(const SmartPtr
<T
>& sptr
) const {
335 return ptr
!= sptr
.ptr
;
339 * Compares a SmartPtr with a plain pointer. They are equal if
340 * both point to the same object.
341 * @return true if both point to the same object
343 bool operator==(const T
* p
) const {
348 * Compares a SmartPtr with a plain pointer. They are unequal if
349 * both point to different objects.
350 * @return true if both point to different objects
352 bool operator!=(const T
* p
) const {
357 * Negates the pointer. True if the pointer is the null pointer
358 * @return true for the null pointer, false otherwise
360 bool operator!() const {
365 * Returns the pointer. The object will still be managed
366 * by the SmartPtr. You must ensure that the pointer
367 * is valid (so don't delete the SmartPtr before you are done with the
369 * @return the plain pointer
378 * Returns the pointer. The object will still be managed
379 * by the SmartPtr. You must ensure that the pointer
380 * is valid (so don't delete the SmartPtr before you are done with the
382 * @return the plain pointer
386 const T
* data() const {
391 * Checks whether both SmartPtrs use the same pointer but two
392 * different reference counts.
393 * If yes, one of them must be 0 (object released), otherwise
395 * @return true if the pointers are used correctly
397 bool isRCCorrect(const SmartPtr
<T
> &p2
) const {
402 return (rc
->refsToObject
== 0) || (p2
.rc
->refsToObject
== 0);
406 * Returns the reference count of the object. The count is 0 if
407 * the object has been released (@ref release()). For the null pointer
408 * the reference count is always 1.
409 * @return the reference count, or 0 for released objects
411 int referenceCount() const {
412 return rc
? rc
->refsToObject
: 1;
416 * Returns a string representation of the pointer.
417 * @return a string representation
419 QString
toString() const {
424 objrcount
= rc
->refsToObject
;
425 rcrcount
= rc
->refsToThis
;
427 return QString("SmartPtr: ptr=%1, refcounts=%2, ptrnum=%3")
428 .arg((int)ptr
).arg(objrcount
).arg(rcrcount
);