1 /* 2 ============================================================================== 3 4 This file is part of the JUCE library. 5 Copyright (c) 2020 - Raw Material Software Limited 6 7 JUCE is an open source library subject to commercial or open-source 8 licensing. 9 10 The code included in this file is provided under the terms of the ISC license 11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission 12 To use, copy, modify, and/or distribute this software for any purpose with or 13 without fee is hereby granted provided that the above copyright notice and 14 this permission notice appear in all copies. 15 16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER 17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE 18 DISCLAIMED. 19 20 ============================================================================== 21 */ 22 23 namespace juce 24 { 25 26 //============================================================================== 27 /** 28 A base class which provides methods for reference-counting. 29 30 To add reference-counting to a class, derive it from this class, and 31 use the ReferenceCountedObjectPtr class to point to it. 32 33 e.g. @code 34 class MyClass : public ReferenceCountedObject 35 { 36 void foo(); 37 38 // This is a neat way of declaring a typedef for a pointer class, 39 // rather than typing out the full templated name each time.. 40 using Ptr = ReferenceCountedObjectPtr<MyClass>; 41 }; 42 43 MyClass::Ptr p = new MyClass(); 44 MyClass::Ptr p2 = p; 45 p = nullptr; 46 p2->foo(); 47 @endcode 48 49 Once a new ReferenceCountedObject has been assigned to a pointer, be 50 careful not to delete the object manually. 51 52 This class uses an Atomic<int> value to hold the reference count, so 53 the reference count can be updated on multiple threads. Note that 54 whilst it's thread-safe to create and delete a ReferenceCountedObjectPtr 55 to a ReferenceCountedObject shared between threads, it's not thread-safe 56 to modify or swap the ReferenceCountedObject. 57 58 For a faster but non-thread-safe version, use SingleThreadedReferenceCountedObject 59 instead. 60 61 @see ReferenceCountedObjectPtr, ReferenceCountedArray, SingleThreadedReferenceCountedObject 62 63 @tags{Core} 64 */ 65 class JUCE_API ReferenceCountedObject 66 { 67 public: 68 //============================================================================== 69 /** Increments the object's reference count. 70 71 This is done automatically by the smart pointer, but is public just 72 in case it's needed for nefarious purposes. 73 */ incReferenceCount()74 void incReferenceCount() noexcept 75 { 76 ++refCount; 77 } 78 79 /** Decreases the object's reference count. 80 If the count gets to zero, the object will be deleted. 81 */ decReferenceCount()82 void decReferenceCount() noexcept 83 { 84 jassert (getReferenceCount() > 0); 85 86 if (--refCount == 0) 87 delete this; 88 } 89 90 /** Decreases the object's reference count. 91 If the count gets to zero, the object will not be deleted, but this method 92 will return true, allowing the caller to take care of deletion. 93 */ decReferenceCountWithoutDeleting()94 bool decReferenceCountWithoutDeleting() noexcept 95 { 96 jassert (getReferenceCount() > 0); 97 return --refCount == 0; 98 } 99 100 /** Returns the object's current reference count. */ getReferenceCount()101 int getReferenceCount() const noexcept { return refCount.get(); } 102 103 104 protected: 105 //============================================================================== 106 /** Creates the reference-counted object (with an initial ref count of zero). */ 107 ReferenceCountedObject() = default; 108 109 /** Copying from another object does not affect this one's reference-count. */ ReferenceCountedObject(const ReferenceCountedObject &)110 ReferenceCountedObject (const ReferenceCountedObject&) noexcept {} 111 /** Copying from another object does not affect this one's reference-count. */ ReferenceCountedObject(ReferenceCountedObject &&)112 ReferenceCountedObject (ReferenceCountedObject&&) noexcept {} 113 /** Copying from another object does not affect this one's reference-count. */ 114 ReferenceCountedObject& operator= (const ReferenceCountedObject&) noexcept { return *this; } 115 /** Copying from another object does not affect this one's reference-count. */ 116 ReferenceCountedObject& operator= (ReferenceCountedObject&&) noexcept { return *this; } 117 118 /** Destructor. */ ~ReferenceCountedObject()119 virtual ~ReferenceCountedObject() 120 { 121 // it's dangerous to delete an object that's still referenced by something else! 122 jassert (getReferenceCount() == 0); 123 } 124 125 /** Resets the reference count to zero without deleting the object. 126 You should probably never need to use this! 127 */ resetReferenceCount()128 void resetReferenceCount() noexcept 129 { 130 refCount = 0; 131 } 132 133 private: 134 //============================================================================== 135 Atomic<int> refCount { 0 }; 136 friend struct ContainerDeletePolicy<ReferenceCountedObject>; 137 }; 138 139 140 //============================================================================== 141 /** 142 Adds reference-counting to an object. 143 144 This is effectively a version of the ReferenceCountedObject class, but which 145 uses a non-atomic counter, and so is not thread-safe (but which will be more 146 efficient). 147 For more details on how to use it, see the ReferenceCountedObject class notes. 148 149 @see ReferenceCountedObject, ReferenceCountedObjectPtr, ReferenceCountedArray 150 151 @tags{Core} 152 */ 153 class JUCE_API SingleThreadedReferenceCountedObject 154 { 155 public: 156 //============================================================================== 157 /** Increments the object's reference count. 158 159 This is done automatically by the smart pointer, but is public just 160 in case it's needed for nefarious purposes. 161 */ 162 void incReferenceCount() noexcept 163 { 164 ++refCount; 165 } 166 167 /** Decreases the object's reference count. 168 If the count gets to zero, the object will be deleted. 169 */ 170 void decReferenceCount() noexcept 171 { 172 jassert (getReferenceCount() > 0); 173 174 if (--refCount == 0) 175 delete this; 176 } 177 178 /** Decreases the object's reference count. 179 If the count gets to zero, the object will not be deleted, but this method 180 will return true, allowing the caller to take care of deletion. 181 */ 182 bool decReferenceCountWithoutDeleting() noexcept 183 { 184 jassert (getReferenceCount() > 0); 185 return --refCount == 0; 186 } 187 188 /** Returns the object's current reference count. */ 189 int getReferenceCount() const noexcept { return refCount; } 190 191 192 protected: 193 //============================================================================== 194 /** Creates the reference-counted object (with an initial ref count of zero). */ 195 SingleThreadedReferenceCountedObject() = default; 196 197 /** Copying from another object does not affect this one's reference-count. */ 198 SingleThreadedReferenceCountedObject (const SingleThreadedReferenceCountedObject&) {} 199 /** Copying from another object does not affect this one's reference-count. */ 200 SingleThreadedReferenceCountedObject (SingleThreadedReferenceCountedObject&&) {} 201 /** Copying from another object does not affect this one's reference-count. */ 202 SingleThreadedReferenceCountedObject& operator= (const SingleThreadedReferenceCountedObject&) { return *this; } 203 /** Copying from another object does not affect this one's reference-count. */ 204 SingleThreadedReferenceCountedObject& operator= (SingleThreadedReferenceCountedObject&&) { return *this; } 205 206 /** Destructor. */ 207 virtual ~SingleThreadedReferenceCountedObject() 208 { 209 // it's dangerous to delete an object that's still referenced by something else! 210 jassert (getReferenceCount() == 0); 211 } 212 213 private: 214 //============================================================================== 215 int refCount = 0; 216 friend struct ContainerDeletePolicy<ReferenceCountedObject>; 217 }; 218 219 220 //============================================================================== 221 /** 222 A smart-pointer class which points to a reference-counted object. 223 224 The template parameter specifies the class of the object you want to point to - the easiest 225 way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject 226 or SingleThreadedReferenceCountedObject, but if you need to, you can roll your own reference-countable 227 class by implementing a set of methods called incReferenceCount(), decReferenceCount(), and 228 decReferenceCountWithoutDeleting(). See ReferenceCountedObject for examples of how these methods 229 should behave. 230 231 When using this class, you'll probably want to create a typedef to abbreviate the full 232 templated name - e.g. 233 @code 234 struct MyClass : public ReferenceCountedObject 235 { 236 using Ptr = ReferenceCountedObjectPtr<MyClass>; 237 ... 238 } 239 @endcode 240 241 @see ReferenceCountedObject, ReferenceCountedObjectArray 242 243 @tags{Core} 244 */ 245 template <class ObjectType> 246 class ReferenceCountedObjectPtr 247 { 248 public: 249 /** The class being referenced by this pointer. */ 250 using ReferencedType = ObjectType; 251 252 //============================================================================== 253 /** Creates a pointer to a null object. */ 254 ReferenceCountedObjectPtr() = default; 255 256 /** Creates a pointer to a null object. */ 257 ReferenceCountedObjectPtr (decltype (nullptr)) noexcept {} 258 259 /** Creates a pointer to an object. 260 This will increment the object's reference-count. 261 */ 262 ReferenceCountedObjectPtr (ReferencedType* refCountedObject) noexcept 263 : referencedObject (refCountedObject) 264 { 265 incIfNotNull (refCountedObject); 266 } 267 268 /** Creates a pointer to an object. 269 This will increment the object's reference-count. 270 */ 271 ReferenceCountedObjectPtr (ReferencedType& refCountedObject) noexcept 272 : referencedObject (&refCountedObject) 273 { 274 refCountedObject.incReferenceCount(); 275 } 276 277 /** Copies another pointer. 278 This will increment the object's reference-count. 279 */ 280 ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr& other) noexcept 281 : referencedObject (other.referencedObject) 282 { 283 incIfNotNull (referencedObject); 284 } 285 286 /** Takes-over the object from another pointer. */ 287 ReferenceCountedObjectPtr (ReferenceCountedObjectPtr&& other) noexcept 288 : referencedObject (other.referencedObject) 289 { 290 other.referencedObject = nullptr; 291 } 292 293 /** Copies another pointer. 294 This will increment the object's reference-count (if it is non-null). 295 */ 296 template <typename Convertible> 297 ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr<Convertible>& other) noexcept 298 : referencedObject (other.get()) 299 { 300 incIfNotNull (referencedObject); 301 } 302 303 /** Changes this pointer to point at a different object. 304 The reference count of the old object is decremented, and it might be 305 deleted if it hits zero. The new object's count is incremented. 306 */ 307 ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr& other) 308 { 309 return operator= (other.referencedObject); 310 } 311 312 /** Changes this pointer to point at a different object. 313 The reference count of the old object is decremented, and it might be 314 deleted if it hits zero. The new object's count is incremented. 315 */ 316 template <typename Convertible> 317 ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr<Convertible>& other) 318 { 319 return operator= (other.get()); 320 } 321 322 /** Changes this pointer to point at a different object. 323 324 The reference count of the old object is decremented, and it might be 325 deleted if it hits zero. The new object's count is incremented. 326 */ 327 ReferenceCountedObjectPtr& operator= (ReferencedType* newObject) 328 { 329 if (newObject != nullptr) 330 return operator= (*newObject); 331 332 reset(); 333 return *this; 334 } 335 336 /** Changes this pointer to point at a different object. 337 338 The reference count of the old object is decremented, and it might be 339 deleted if it hits zero. The new object's count is incremented. 340 */ 341 ReferenceCountedObjectPtr& operator= (ReferencedType& newObject) 342 { 343 if (referencedObject != &newObject) 344 { 345 newObject.incReferenceCount(); 346 auto* oldObject = referencedObject; 347 referencedObject = &newObject; 348 decIfNotNull (oldObject); 349 } 350 351 return *this; 352 } 353 354 /** Resets this pointer to a null pointer. */ 355 ReferenceCountedObjectPtr& operator= (decltype (nullptr)) 356 { 357 reset(); 358 return *this; 359 } 360 361 /** Takes-over the object from another pointer. */ 362 ReferenceCountedObjectPtr& operator= (ReferenceCountedObjectPtr&& other) noexcept 363 { 364 std::swap (referencedObject, other.referencedObject); 365 return *this; 366 } 367 368 /** Destructor. 369 This will decrement the object's reference-count, which will cause the 370 object to be deleted when the ref-count hits zero. 371 */ 372 ~ReferenceCountedObjectPtr() 373 { 374 decIfNotNull (referencedObject); 375 } 376 377 //============================================================================== 378 /** Returns the object that this pointer references. 379 The pointer returned may be null, of course. 380 */ 381 ReferencedType* get() const noexcept { return referencedObject; } 382 383 /** Resets this object to a null pointer. */ 384 void reset() noexcept 385 { 386 auto oldObject = referencedObject; // need to null the pointer before deleting the object 387 referencedObject = nullptr; // in case this ptr is itself deleted as a side-effect 388 decIfNotNull (oldObject); // of the destructor 389 } 390 391 // the -> operator is called on the referenced object 392 ReferencedType* operator->() const noexcept 393 { 394 jassert (referencedObject != nullptr); // null pointer method call! 395 return referencedObject; 396 } 397 398 /** Dereferences the object that this pointer references. 399 The pointer returned may be null, of course. 400 */ 401 ReferencedType& operator*() const noexcept { jassert (referencedObject != nullptr); return *referencedObject; } 402 403 /** Checks whether this pointer is null */ 404 bool operator== (decltype (nullptr)) const noexcept { return referencedObject == nullptr; } 405 /** Checks whether this pointer is null */ 406 bool operator!= (decltype (nullptr)) const noexcept { return referencedObject != nullptr; } 407 408 /** Compares two ReferenceCountedObjectPtrs. */ 409 bool operator== (const ObjectType* other) const noexcept { return referencedObject == other; } 410 /** Compares two ReferenceCountedObjectPtrs. */ 411 bool operator== (const ReferenceCountedObjectPtr& other) const noexcept { return referencedObject == other.get(); } 412 /** Compares two ReferenceCountedObjectPtrs. */ 413 bool operator!= (const ObjectType* other) const noexcept { return referencedObject != other; } 414 /** Compares two ReferenceCountedObjectPtrs. */ 415 bool operator!= (const ReferenceCountedObjectPtr& other) const noexcept { return referencedObject != other.get(); } 416 417 #if JUCE_STRICT_REFCOUNTEDPOINTER 418 /** Checks whether this pointer is null */ 419 explicit operator bool() const noexcept { return referencedObject != nullptr; } 420 421 #else 422 /** Returns the object that this pointer references. 423 The pointer returned may be null, of course. 424 Note that this methods allows the compiler to be very lenient with what it allows you to do 425 with the pointer, it's safer to disable this by setting JUCE_STRICT_REFCOUNTEDPOINTER=1, which 426 increased type safety and can prevent some common slip-ups. 427 */ 428 operator ReferencedType*() const noexcept { return referencedObject; } 429 #endif 430 431 432 // This old method is deprecated in favour of the shorter and more standard get() method. 433 JUCE_DEPRECATED_WITH_BODY (ReferencedType* getObject() const, { return get(); }) 434 435 private: 436 //============================================================================== 437 ReferencedType* referencedObject = nullptr; 438 439 static void incIfNotNull (ReferencedType* o) noexcept 440 { 441 if (o != nullptr) 442 o->incReferenceCount(); 443 } 444 445 static void decIfNotNull (ReferencedType* o) noexcept 446 { 447 if (o != nullptr && o->decReferenceCountWithoutDeleting()) 448 ContainerDeletePolicy<ReferencedType>::destroy (o); 449 } 450 }; 451 452 453 //============================================================================== 454 /** Compares two ReferenceCountedObjectPtrs. */ 455 template <typename Type> 456 bool operator== (const Type* object1, const ReferenceCountedObjectPtr<Type>& object2) noexcept 457 { 458 return object1 == object2.get(); 459 } 460 461 /** Compares two ReferenceCountedObjectPtrs. */ 462 template <typename Type> 463 bool operator!= (const Type* object1, const ReferenceCountedObjectPtr<Type>& object2) noexcept 464 { 465 return object1 != object2.get(); 466 } 467 468 } // namespace juce 469