diff --git a/modules/juce_core/containers/juce_ReferenceCountedArray.h b/modules/juce_core/containers/juce_ReferenceCountedArray.h index bf88b4cbeb..fba2fa4133 100644 --- a/modules/juce_core/containers/juce_ReferenceCountedArray.h +++ b/modules/juce_core/containers/juce_ReferenceCountedArray.h @@ -32,7 +32,15 @@ //============================================================================== /** - Holds a list of objects derived from ReferenceCountedObject. + Holds a list of objects derived from ReferenceCountedObject, or which implement basic + reference-count handling methods. + + The template parameter specifies the class of the object you want to point to - the easiest + way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject + or SingleThreadedReferenceCountedObject, but if you need to, you can roll your own reference-countable + class by implementing a set of mathods called incReferenceCount(), decReferenceCount(), and + decReferenceCountWithoutDeleting(). See ReferenceCountedObject for examples of how these methods + should behave. A ReferenceCountedArray holds objects derived from ReferenceCountedObject, and takes care of incrementing and decrementing their ref counts when they @@ -125,7 +133,7 @@ public: while (numUsed > 0) if (ObjectClass* o = data.elements [--numUsed]) - o->decReferenceCount(); + releaseObject (o); jassert (numUsed == 0); data.setAllocatedSize (0); @@ -387,7 +395,7 @@ public: if (indexToChange < numUsed) { if (ObjectClass* o = data.elements [indexToChange]) - o->decReferenceCount(); + releaseObject (o); data.elements [indexToChange] = newObject; } @@ -537,7 +545,7 @@ public: ObjectClass** const e = data.elements + indexToRemove; if (ObjectClass* o = *e) - o->decReferenceCount(); + releaseObject (o); --numUsed; const int numberToShift = numUsed - indexToRemove; @@ -571,7 +579,7 @@ public: if (ObjectClass* o = *e) { removedItem = o; - o->decReferenceCount(); + releaseObject (o); } --numUsed; @@ -631,7 +639,7 @@ public: { if (ObjectClass* o = data.elements[i]) { - o->decReferenceCount(); + releaseObject (o); data.elements[i] = nullptr; // (in case one of the destructors accesses this array and hits a dangling pointer) } } @@ -863,6 +871,12 @@ private: //============================================================================== ArrayAllocationBase data; int numUsed; + + static void releaseObject (ObjectClass* o) + { + if (o->decReferenceCountWithoutDeleting()) + ContainerDeletePolicy::destroy (o); + } }; diff --git a/modules/juce_core/memory/juce_ReferenceCountedObject.h b/modules/juce_core/memory/juce_ReferenceCountedObject.h index 7cad884143..8dfb20198b 100644 --- a/modules/juce_core/memory/juce_ReferenceCountedObject.h +++ b/modules/juce_core/memory/juce_ReferenceCountedObject.h @@ -32,7 +32,7 @@ //============================================================================== /** - Adds reference-counting to an object. + A base class which provides methods for reference-counting. To add reference-counting to a class, derive it from this class, and use the ReferenceCountedObjectPtr class to point to it. @@ -71,16 +71,15 @@ public: This is done automatically by the smart pointer, but is public just in case it's needed for nefarious purposes. */ - inline void incReferenceCount() noexcept + void incReferenceCount() noexcept { ++refCount; } /** Decreases the object's reference count. - If the count gets to zero, the object will be deleted. */ - inline void decReferenceCount() noexcept + void decReferenceCount() noexcept { jassert (getReferenceCount() > 0); @@ -88,16 +87,24 @@ public: delete this; } + /** Decreases the object's reference count. + If the count gets to zero, the object will not be deleted, but this method + will return true, allowing the caller to take care of deletion. + */ + bool decReferenceCountWithoutDeleting() noexcept + { + jassert (getReferenceCount() > 0); + return --refCount == 0; + } + /** Returns the object's current reference count. */ - inline int getReferenceCount() const noexcept { return refCount.get(); } + int getReferenceCount() const noexcept { return refCount.get(); } protected: //============================================================================== /** Creates the reference-counted object (with an initial ref count of zero). */ - ReferenceCountedObject() - { - } + ReferenceCountedObject() {} /** Destructor. */ virtual ~ReferenceCountedObject() @@ -118,6 +125,7 @@ private: //============================================================================== Atomic refCount; + friend struct ContainerDeletePolicy; JUCE_DECLARE_NON_COPYABLE (ReferenceCountedObject) }; @@ -142,16 +150,15 @@ public: This is done automatically by the smart pointer, but is public just in case it's needed for nefarious purposes. */ - inline void incReferenceCount() noexcept + void incReferenceCount() noexcept { ++refCount; } /** Decreases the object's reference count. - If the count gets to zero, the object will be deleted. */ - inline void decReferenceCount() noexcept + void decReferenceCount() noexcept { jassert (getReferenceCount() > 0); @@ -159,8 +166,18 @@ public: delete this; } + /** Decreases the object's reference count. + If the count gets to zero, the object will not be deleted, but this method + will return true, allowing the caller to take care of deletion. + */ + bool decReferenceCountWithoutDeleting() noexcept + { + jassert (getReferenceCount() > 0); + return --refCount == 0; + } + /** Returns the object's current reference count. */ - inline int getReferenceCount() const noexcept { return refCount; } + int getReferenceCount() const noexcept { return refCount; } protected: @@ -179,6 +196,7 @@ private: //============================================================================== int refCount; + friend struct ContainerDeletePolicy; JUCE_DECLARE_NON_COPYABLE (SingleThreadedReferenceCountedObject) }; @@ -188,13 +206,20 @@ private: A smart-pointer class which points to a reference-counted object. The template parameter specifies the class of the object you want to point to - the easiest - way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject, - but if you need to, you could roll your own reference-countable class by implementing a pair of - mathods called incReferenceCount() and decReferenceCount(). + way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject + or SingleThreadedReferenceCountedObject, but if you need to, you can roll your own reference-countable + class by implementing a set of mathods called incReferenceCount(), decReferenceCount(), and + decReferenceCountWithoutDeleting(). See ReferenceCountedObject for examples of how these methods + should behave. When using this class, you'll probably want to create a typedef to abbreviate the full templated name - e.g. - @code typedef ReferenceCountedObjectPtr MyClassPtr;@endcode + @code + struct MyClass : public ReferenceCountedObject + { + typedef ReferenceCountedObjectPtr Ptr; + ... + @endcode @see ReferenceCountedObject, ReferenceCountedObjectArray */ @@ -207,54 +232,40 @@ public: //============================================================================== /** Creates a pointer to a null object. */ - inline ReferenceCountedObjectPtr() noexcept + ReferenceCountedObjectPtr() noexcept : referencedObject (nullptr) { } /** Creates a pointer to an object. - - This will increment the object's reference-count if it is non-null. + This will increment the object's reference-count. */ - inline ReferenceCountedObjectPtr (ReferenceCountedObjectClass* const refCountedObject) noexcept + ReferenceCountedObjectPtr (ReferencedType* refCountedObject) noexcept : referencedObject (refCountedObject) { - if (refCountedObject != nullptr) - refCountedObject->incReferenceCount(); + incIfNotNull (refCountedObject); } /** Copies another pointer. - This will increment the object's reference-count (if it is non-null). + This will increment the object's reference-count. */ - inline ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr& other) noexcept - : referencedObject (other.referencedObject) - { - if (referencedObject != nullptr) - referencedObject->incReferenceCount(); - } - - #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS - /** Takes-over the object from another pointer. */ - inline ReferenceCountedObjectPtr (ReferenceCountedObjectPtr&& other) noexcept + ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr& other) noexcept : referencedObject (other.referencedObject) { - other.referencedObject = nullptr; + incIfNotNull (referencedObject); } - #endif /** Copies another pointer. This will increment the object's reference-count (if it is non-null). */ template - inline ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr& other) noexcept - : referencedObject (static_cast (other.get())) + ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr& other) noexcept + : referencedObject (static_cast (other.get())) { - if (referencedObject != nullptr) - referencedObject->incReferenceCount(); + incIfNotNull (referencedObject); } /** Changes this pointer to point at a different object. - The reference count of the old object is decremented, and it might be deleted if it hits zero. The new object's count is incremented. */ @@ -264,94 +275,100 @@ public: } /** Changes this pointer to point at a different object. - The reference count of the old object is decremented, and it might be deleted if it hits zero. The new object's count is incremented. */ template ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr& other) { - return operator= (static_cast (other.get())); - } - - #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS - /** Takes-over the object from another pointer. */ - ReferenceCountedObjectPtr& operator= (ReferenceCountedObjectPtr&& other) - { - std::swap (referencedObject, other.referencedObject); - return *this; + return operator= (static_cast (other.get())); } - #endif /** Changes this pointer to point at a different object. The reference count of the old object is decremented, and it might be deleted if it hits zero. The new object's count is incremented. */ - ReferenceCountedObjectPtr& operator= (ReferenceCountedObjectClass* const newObject) + ReferenceCountedObjectPtr& operator= (ReferencedType* const newObject) { if (referencedObject != newObject) { - if (newObject != nullptr) - newObject->incReferenceCount(); - - ReferenceCountedObjectClass* const oldObject = referencedObject; + incIfNotNull (newObject); + ReferencedType* const oldObject = referencedObject; referencedObject = newObject; - - if (oldObject != nullptr) - oldObject->decReferenceCount(); + decIfNotNull (oldObject); } return *this; } - /** Destructor. - - This will decrement the object's reference-count, and may delete it if it - gets to zero. - */ - inline ~ReferenceCountedObjectPtr() + #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS + /** Takes-over the object from another pointer. */ + ReferenceCountedObjectPtr (ReferenceCountedObjectPtr&& other) noexcept + : referencedObject (other.referencedObject) { - if (referencedObject != nullptr) - referencedObject->decReferenceCount(); + other.referencedObject = nullptr; } - /** Returns the object that this pointer references. - The pointer returned may be zero, of course. - */ - inline operator ReferenceCountedObjectClass*() const noexcept + /** Takes-over the object from another pointer. */ + ReferenceCountedObjectPtr& operator= (ReferenceCountedObjectPtr&& other) { - return referencedObject; + std::swap (referencedObject, other.referencedObject); + return *this; } + #endif - // the -> operator is called on the referenced object - inline ReferenceCountedObjectClass* operator->() const noexcept + /** Destructor. + This will decrement the object's reference-count, which will cause the + object to be deleted when the ref-count hits zero. + */ + ~ReferenceCountedObjectPtr() { - return referencedObject; + decIfNotNull (referencedObject); } + //============================================================================== /** Returns the object that this pointer references. The pointer returned may be zero, of course. */ - inline ReferenceCountedObjectClass* get() const noexcept - { - return referencedObject; - } + operator ReferencedType*() const noexcept { return referencedObject; } + + /** Returns the object that this pointer references. + The pointer returned may be zero, of course. + */ + ReferencedType* get() const noexcept { return referencedObject; } /** Returns the object that this pointer references. The pointer returned may be zero, of course. */ - inline ReferenceCountedObjectClass* getObject() const noexcept + ReferencedType* getObject() const noexcept { return referencedObject; } + + // the -> operator is called on the referenced object + ReferencedType* operator->() const noexcept { + jassert (referencedObject != nullptr); // null pointer method call! return referencedObject; } private: //============================================================================== - ReferenceCountedObjectClass* referencedObject; + ReferencedType* referencedObject; + + static void incIfNotNull (ReferencedType* o) noexcept + { + if (o != nullptr) + o->incReferenceCount(); + } + + static void decIfNotNull (ReferencedType* o) noexcept + { + if (o != nullptr && o->decReferenceCountWithoutDeleting()) + ContainerDeletePolicy::destroy (o); + } }; +//============================================================================== /** Compares two ReferenceCountedObjectPointers. */ template bool operator== (const ReferenceCountedObjectPtr& object1, ReferenceCountedObjectClass* const object2) noexcept