File indexing completed on 2024-05-12 15:56:59
0001 /* 0002 * SPDX-FileCopyrightText: 2005 Frerich Raabe <raabe@kde.org> 0003 * SPDX-FileCopyrightText: 2006, 2010 Cyrille Berger <cberger@cberger.net> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #ifndef KIS_SHAREDPTR_H 0009 #define KIS_SHAREDPTR_H 0010 0011 #include <QtGlobal> 0012 0013 #include <kis_debug.h> 0014 0015 #include "kis_memory_leak_tracker.h" 0016 0017 template<class T> 0018 class KisWeakSharedPtr; 0019 0020 /** 0021 * KisSharedPtr is a shared pointer similar to KSharedPtr and 0022 * boost::shared_ptr. The difference with KSharedPtr is that our 0023 * constructor is not explicit. 0024 * 0025 * A shared pointer is a wrapper around a real pointer. The shared 0026 * pointer keeps a reference count, and when the reference count drops 0027 * to 0 the contained pointer is deleted. You can use the shared 0028 * pointer just as you would use a real pointer. 0029 * 0030 * See also also item 28 and 29 of More Effective C++ and 0031 * https://bugs.kde.org/show_bug.cgi?id=52261 as well as 0032 * https://www.boost.org/libs/smart_ptr/shared_ptr.htm. 0033 * 0034 * Advantage of KisSharedPtr over boost pointer or QSharedPointer? 0035 * 0036 * The difference with boost share pointer is that in 0037 * boost::shared_ptr, the counter is kept inside the smart pointer, 0038 * meaning that you should never never remove the pointer from its 0039 * smart pointer object, because if you do that, and somewhere in the 0040 * code, the pointer is put back in a smart pointer, then you have two 0041 * counters, and when one reach zero, then the object gets deleted 0042 * while some other code thinks the pointer is still valid. 0043 * 0044 * Disadvantage of KisSharedPtr compared to boost pointer? 0045 * 0046 * KisSharedPtr requires the class to inherits KisShared. 0047 * 0048 * Difference with QSharedPointer 0049 * 0050 * QSharedPointer and KisSharedPtr are very similar, but 0051 * QSharedPointer has an explicit constructor which makes it more 0052 * painful to use in some constructions. And QSharedPointer 0053 * doesn't offer a weak pointer. 0054 */ 0055 template<class T> 0056 class KisSharedPtr 0057 { 0058 friend class KisWeakSharedPtr<T>; 0059 public: 0060 /** 0061 * Creates a null pointer. 0062 */ 0063 inline KisSharedPtr() 0064 : d(0) { } 0065 0066 /** 0067 * Creates a new pointer. 0068 * @param p the pointer 0069 */ 0070 inline KisSharedPtr(T* p) 0071 : d(p) { 0072 ref(); 0073 } 0074 0075 inline KisSharedPtr(const KisWeakSharedPtr<T>& o); 0076 0077 // Free the pointer and set it to new value 0078 void attach(T* p); 0079 0080 // Free the pointer 0081 void clear(); 0082 0083 /** 0084 * Copies a pointer. 0085 * @param o the pointer to copy 0086 */ 0087 inline KisSharedPtr<T>(const KisSharedPtr<T>& o) 0088 : d(o.d) { 0089 ref(); 0090 } 0091 0092 /** 0093 * Dereferences the object that this pointer points to. If it was 0094 * the last reference, the object will be deleted. 0095 */ 0096 inline ~KisSharedPtr() { 0097 deref(); 0098 } 0099 0100 inline KisSharedPtr<T>& operator= (const KisSharedPtr& o) { 0101 attach(o.d); 0102 return *this; 0103 } 0104 inline bool operator== (const T* p) const { 0105 return (d == p); 0106 } 0107 inline bool operator!= (const T* p) const { 0108 return (d != p); 0109 } 0110 inline bool operator== (const KisSharedPtr& o) const { 0111 return (d == o.d); 0112 } 0113 inline bool operator!= (const KisSharedPtr& o) const { 0114 return (d != o.d); 0115 } 0116 0117 inline KisSharedPtr<T>& operator= (T* p) { 0118 attach(p); 0119 return *this; 0120 } 0121 0122 inline operator const T*() const { 0123 return d; 0124 } 0125 0126 template< class T2> inline operator KisSharedPtr<T2>() const { 0127 return KisSharedPtr<T2>(d); 0128 } 0129 0130 /** 0131 * @return the contained pointer. If you delete the contained 0132 * pointer, you will make KisSharedPtr very unhappy. It is 0133 * perfectly safe to put the contained pointer in another 0134 * KisSharedPtr, though. 0135 */ 0136 inline T* data() { 0137 return d; 0138 } 0139 0140 /** 0141 * @return the pointer 0142 */ 0143 inline const T* data() const { 0144 return d; 0145 } 0146 0147 /** 0148 * @return a const pointer to the shared object. 0149 */ 0150 inline const T* constData() const { 0151 return d; 0152 } 0153 0154 inline const T& operator*() const { 0155 Q_ASSERT(d); 0156 return *d; 0157 } 0158 inline T& operator*() { 0159 Q_ASSERT(d); 0160 return *d; 0161 } 0162 0163 inline const T* operator->() const { 0164 Q_ASSERT(d); 0165 return d; 0166 } 0167 inline T* operator->() { 0168 Q_ASSERT(d); 0169 return d; 0170 } 0171 0172 /** 0173 * @return true if the pointer is null 0174 */ 0175 inline bool isNull() const { 0176 return (d == 0); 0177 } 0178 0179 inline static void ref(const KisSharedPtr<T>* sp, T* t) 0180 { 0181 #ifndef HAVE_MEMORY_LEAK_TRACKER 0182 Q_UNUSED(sp); 0183 #else 0184 KisMemoryLeakTracker::instance()->reference(t, sp); 0185 #endif 0186 if (t) { 0187 t->ref(); 0188 } 0189 } 0190 0191 inline static bool deref(const KisSharedPtr<T>* sp, T* t) 0192 { 0193 #ifndef HAVE_MEMORY_LEAK_TRACKER 0194 Q_UNUSED(sp); 0195 #else 0196 KisMemoryLeakTracker::instance()->dereference(t, sp); 0197 #endif 0198 if (t && !t->deref()) { 0199 delete t; 0200 return false; 0201 } 0202 return true; 0203 } 0204 0205 private: 0206 inline void ref() const 0207 { 0208 ref(this, d); 0209 } 0210 0211 inline void deref() const 0212 { 0213 bool v = deref(this, d); 0214 #ifndef NDEBUG 0215 if (!v) { 0216 d = 0; 0217 } 0218 #else 0219 Q_UNUSED(v); 0220 #endif 0221 } 0222 0223 private: 0224 mutable T* d; 0225 }; 0226 0227 /** 0228 * A weak shared ptr is an ordinary shared ptr, with two differences: 0229 * it doesn't delete the contained pointer if the refcount drops to 0230 * zero and it doesn't prevent the contained pointer from being 0231 * deleted if the last strong shared pointer goes out of scope. 0232 */ 0233 template<class T> 0234 class KisWeakSharedPtr 0235 { 0236 friend class KisSharedPtr<T>; 0237 public: 0238 /** 0239 * Creates a null pointer. 0240 */ 0241 inline KisWeakSharedPtr() 0242 : d(0), weakReference(0) { } 0243 0244 /** 0245 * Creates a new pointer. 0246 * @param p the pointer 0247 */ 0248 inline KisWeakSharedPtr(T* p) { 0249 load(p); 0250 } 0251 0252 inline KisWeakSharedPtr<T>(const KisSharedPtr<T>& o) { 0253 load(o.d); 0254 } 0255 0256 /** 0257 * Copies a pointer. 0258 * @param o the pointer to copy 0259 */ 0260 inline KisWeakSharedPtr<T>(const KisWeakSharedPtr<T>& o) { 0261 if (o.isConsistent()) { 0262 load(o.d); 0263 } 0264 else { 0265 d = 0; 0266 weakReference = 0; 0267 } 0268 } 0269 0270 inline ~KisWeakSharedPtr() { 0271 detach(); 0272 } 0273 0274 inline KisWeakSharedPtr<T>& operator= (const KisWeakSharedPtr& o) { 0275 attach(o); 0276 return *this; 0277 } 0278 0279 inline bool operator== (const T* p) const { 0280 return (d == p); 0281 } 0282 inline bool operator!= (const T* p) const { 0283 return (d != p); 0284 } 0285 inline bool operator== (const KisWeakSharedPtr& o) const { 0286 return (d == o.d); 0287 } 0288 inline bool operator!= (const KisWeakSharedPtr& o) const { 0289 return (d != o.d); 0290 } 0291 0292 inline KisWeakSharedPtr<T>& operator= (T* p) { 0293 attach(p); 0294 return *this; 0295 } 0296 0297 template< class T2> inline operator KisWeakSharedPtr<T2>() const { 0298 return KisWeakSharedPtr<T2>(d); 0299 } 0300 0301 /** 0302 * Note that if you use this function, the pointer might be destroyed 0303 * if KisSharedPtr pointing to this pointer are deleted, resulting in 0304 * a segmentation fault. Use with care. 0305 * @return a const pointer to the shared object. 0306 */ 0307 inline T* data() { 0308 if (!isConsistent()) { 0309 warnKrita.noquote() << kisBacktrace(); 0310 Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!"); 0311 } 0312 0313 return d; 0314 } 0315 0316 /** 0317 * @see data() 0318 */ 0319 inline const T* data() const { 0320 if (!isConsistent()) { 0321 warnKrita.noquote() << kisBacktrace(); 0322 Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!"); 0323 } 0324 0325 return d; 0326 } 0327 0328 /** 0329 * @see data() 0330 */ 0331 inline const T* constData() const { 0332 if (!isConsistent()) { 0333 warnKrita.noquote() << kisBacktrace(); 0334 Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!"); 0335 } 0336 0337 return d; 0338 } 0339 0340 /** 0341 * @see data() 0342 */ 0343 inline operator const T*() const { 0344 /** 0345 * This operator is used in boolean expressions where we check 0346 * for pointer consistency, so return 0 instead of asserting. 0347 */ 0348 0349 return isConsistent() ? d : 0; 0350 } 0351 0352 inline const T& operator*() const { 0353 if (!isValid()) { 0354 warnKrita.noquote() << kisBacktrace(); 0355 Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!"); 0356 } 0357 0358 return *d; 0359 } 0360 0361 inline T& operator*() { 0362 if (!isValid()) { 0363 warnKrita.noquote() << kisBacktrace(); 0364 Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!"); 0365 } 0366 0367 return *d; 0368 } 0369 0370 inline const T* operator->() const { 0371 if (!isValid()) { 0372 warnKrita.noquote() << kisBacktrace(); 0373 Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!"); 0374 } 0375 0376 return d; 0377 } 0378 0379 inline T* operator->() { 0380 if (!isValid()) { 0381 warnKrita.noquote() << kisBacktrace(); 0382 Q_ASSERT_X(0, "KisWeakSharedPtr", "Weak pointer is not valid!"); 0383 } 0384 0385 return d; 0386 } 0387 0388 /** 0389 * @return true if the pointer is null 0390 */ 0391 inline bool isNull() const { 0392 return (d == 0); 0393 } 0394 0395 /** 0396 * @return true if the weak pointer points to a valid pointer 0397 * and false if the data has been deleted or is null 0398 */ 0399 inline bool isValid() const { 0400 Q_ASSERT(!d || weakReference); 0401 0402 return d && weakReference && isOdd((int)*weakReference); 0403 } 0404 0405 /** 0406 * @brief toStrongRef returns a KisSharedPtr which may be dereferenced. 0407 * 0408 * Weak pointers should only be used to track ownership but never be used as pointers. 0409 * This has historically not been the case, but in new API this function should be used 0410 * instead of directly using a weak pointer as pointer. 0411 * @return a KisSharedPtr, which may be null 0412 */ 0413 inline KisSharedPtr<T> toStrongRef() const { 0414 return KisSharedPtr<T>(*this); 0415 } 0416 0417 private: 0418 static const qint32 WEAK_REF = 2; 0419 static inline bool isOdd(const qint32 &x) { 0420 return x & 0x01; 0421 } 0422 0423 inline bool isConsistent() const { 0424 Q_ASSERT(!d || weakReference); 0425 0426 return !d || (weakReference && isOdd((int)*weakReference)); 0427 } 0428 0429 void load(T* newValue) { 0430 d = newValue; 0431 0432 if (d) { 0433 weakReference = d->sharedWeakReference(); 0434 weakReference->fetchAndAddOrdered(WEAK_REF); 0435 } 0436 else { 0437 weakReference = 0; 0438 } 0439 } 0440 0441 // see note in kis_shared.cc 0442 inline void attach(T* newValue) { 0443 detach(); 0444 load(newValue); 0445 } 0446 0447 inline void attach(const KisWeakSharedPtr& o) { 0448 detach(); 0449 if (o.isConsistent()) { 0450 load(o.d); 0451 } 0452 else { 0453 d = 0; 0454 weakReference = 0; 0455 } 0456 } 0457 0458 // see note in kis_shared.cc 0459 void detach() { 0460 d = 0; 0461 0462 if (weakReference && 0463 weakReference->fetchAndAddOrdered(-WEAK_REF) <= WEAK_REF) { 0464 0465 // sanity check: 0466 Q_ASSERT((int)*weakReference == 0); 0467 0468 delete weakReference; 0469 weakReference = 0; 0470 } 0471 } 0472 0473 mutable T* d; 0474 QAtomicInt *weakReference; 0475 }; 0476 0477 0478 template <class T> 0479 Q_INLINE_TEMPLATE KisSharedPtr<T>::KisSharedPtr(const KisWeakSharedPtr<T>& o) 0480 : d(o.d) 0481 { 0482 if (o.isValid()) { 0483 ref(); 0484 0485 /** 0486 * Thread safety: 0487 * Is the object we have just referenced still valid? 0488 */ 0489 Q_ASSERT(o.isConsistent()); 0490 } 0491 else { 0492 d = 0; 0493 } 0494 } 0495 0496 0497 template <class T> 0498 Q_INLINE_TEMPLATE void KisSharedPtr<T>::attach(T* p) 0499 { 0500 if (d != p) { 0501 ref(this, p); 0502 T* old = d; 0503 d = p; 0504 deref(this, old); 0505 } 0506 } 0507 0508 template <class T> 0509 Q_INLINE_TEMPLATE void KisSharedPtr<T>::clear() 0510 { 0511 attach((T*)0); 0512 } 0513 0514 #endif