Browse Source

Changes to ReferenceCountedObject to support more flexible deletion via ContainerDeletePolicy.

tags/2021-05-28
jules 11 years ago
parent
commit
954312b23c
2 changed files with 118 additions and 87 deletions
  1. +20
    -6
      modules/juce_core/containers/juce_ReferenceCountedArray.h
  2. +98
    -81
      modules/juce_core/memory/juce_ReferenceCountedObject.h

+ 20
- 6
modules/juce_core/containers/juce_ReferenceCountedArray.h View File

@@ -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 <ObjectClass*, TypeOfCriticalSectionToUse> data;
int numUsed;
static void releaseObject (ObjectClass* o)
{
if (o->decReferenceCountWithoutDeleting())
ContainerDeletePolicy<ObjectClass>::destroy (o);
}
};


+ 98
- 81
modules/juce_core/memory/juce_ReferenceCountedObject.h View File

@@ -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 <int> refCount;
friend struct ContainerDeletePolicy<ReferenceCountedObject>;
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<ReferenceCountedObject>;
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<MyClass> MyClassPtr;@endcode
@code
struct MyClass : public ReferenceCountedObject
{
typedef ReferenceCountedObjectPtr<MyClass> 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 <class DerivedClass>
inline ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr<DerivedClass>& other) noexcept
: referencedObject (static_cast <ReferenceCountedObjectClass*> (other.get()))
ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr<DerivedClass>& other) noexcept
: referencedObject (static_cast <ReferencedType*> (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 <class DerivedClass>
ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr<DerivedClass>& other)
{
return operator= (static_cast <ReferenceCountedObjectClass*> (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<ReferencedType*> (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<ReferencedType>::destroy (o);
}
};
//==============================================================================
/** Compares two ReferenceCountedObjectPointers. */
template <class ReferenceCountedObjectClass>
bool operator== (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, ReferenceCountedObjectClass* const object2) noexcept


Loading…
Cancel
Save