fix remaining krazy issues
[kdenetwork.git] / krdc / smartptr.h
blob4a3698fa0119d44adba2199771166237a328151e
1 /***************************************************************************
2 begin : Wed Jan 1 17:56 CET 2003
3 copyright : (C) 2003 by Tim Jansen
4 email : tim@tjansen.de
5 ***************************************************************************/
7 /***************************************************************************
8 * *
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. *
13 * *
14 ***************************************************************************/
16 #ifndef SMARTPTR_H
17 #define SMARTPTR_H
19 #include <QString>
21 class WeakPtr;
23 /**
24 * @internal
26 struct SmartPtrRefCount {
27 SmartPtrRefCount(int toObj, int toThis) :
28 refsToObject(toObj),
29 refsToThis(toThis) {
31 int refsToObject; // number of pointers to the object, 0 if released
32 int refsToThis; // number of pointer to the ref count
35 /**
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
50 * deletes the object.
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.
61 * @see WeakPtr
63 template <class T>
64 class SmartPtr
66 public: // members are public because of problems with gcc 3.2
67 friend class WeakPtr;
69 /// @internal
70 T* ptr;
71 /// @internal
72 mutable SmartPtrRefCount *rc; // if !rc, refcount=1 is assumed
74 protected:
75 void freePtr() {
76 if (!ptr)
77 return;
78 if (!rc)
79 delete ptr;
80 else {
81 if (rc->refsToObject > 0) {
82 Q_ASSERT(rc->refsToObject >= rc->refsToThis);
83 if (rc->refsToObject == 1) {
84 delete ptr;
85 rc->refsToObject = -1;
87 else
88 rc->refsToObject--;
90 rc->refsToThis--;
91 if (rc->refsToThis < 1)
92 delete rc;
96 void init(T *sptr, SmartPtrRefCount *&orc)
98 ptr = sptr;
99 if (!sptr)
100 rc = 0;
101 else if (!orc) {
102 orc = new SmartPtrRefCount(2, 2);
103 rc = orc;
105 else {
106 rc = orc;
107 rc->refsToThis++;
108 if (rc->refsToObject) {
109 // prevent initialization from invalid WeakPtr
110 Q_ASSERT(rc->refsToObject > 0);
111 rc->refsToObject++;
116 SmartPtr(T *p, SmartPtrRefCount *&orc)
118 init(p, orc);
121 public:
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
126 * has been deleted.
127 * @param p the pointer to the object to manage, or the null pointer
129 SmartPtr(T* p = 0) :
130 ptr(p),
131 rc(0)
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
152 template<class T2>
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.
162 ~SmartPtr() {
163 freePtr();
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) {
175 if (this == &sptr)
176 return *this;
178 freePtr();
179 init(sptr.ptr, sptr.rc);
180 return *this;
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
191 template<class T2>
192 SmartPtr &operator=(const SmartPtr<T2> &sptr) {
193 if (this == static_cast<SmartPtr<T> >(&sptr))
194 return *this;
196 freePtr();
197 init(static_cast<T>(sptr.ptr), sptr.rc);
198 return *this;
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
206 void set(T *p) {
207 if (ptr == p)
208 return;
209 freePtr();
211 ptr = p;
212 rc = 0;
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
224 * @see data()
226 T* release() {
227 if (!rc)
228 rc = new SmartPtrRefCount(0, 1);
229 else
230 rc->refsToObject = 0;
231 return ptr;
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) {
241 set(p);
242 return *this;
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 {
251 return ptr != 0;
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
258 * plain pointer).
259 * @return the plain pointer
260 * @see data()
261 * @see release()
262 * @see WeakPtr
264 template<class T2>
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
273 * plain pointer).
274 * @return the plain pointer
275 * @see data()
276 * @see release()
277 * @see WeakPtr
279 template<class T2>
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
289 T& operator*() {
290 return *ptr;
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 {
299 return *ptr;
303 * Access a member of the pointed object. This works exactly
304 * like on a regular pointer.
305 * @return the pointer
307 T* operator->() {
308 return ptr;
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 {
317 return ptr;
321 * Compares two SmartPtrs. They are equal if both point to the
322 * same object.
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
331 * different objects.
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 {
344 return ptr == p;
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 {
353 return ptr != p;
356 /**
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 {
361 return ptr == 0;
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
368 * plain pointer).
369 * @return the plain pointer
370 * @see release()
371 * @see WeakPtr
373 T* data() {
374 return ptr;
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
381 * plain pointer).
382 * @return the plain pointer
383 * @see release()
384 * @see WeakPtr
386 const T* data() const {
387 return ptr;
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
394 * it is an error.
395 * @return true if the pointers are used correctly
397 bool isRCCorrect(const SmartPtr<T> &p2) const {
398 if (ptr == p2.ptr)
399 return true;
400 if (rc == p2.rc)
401 return true;
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 {
420 int objrcount = 1;
421 int rcrcount = 0;
423 if (rc) {
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);
433 #endif