/** @file ReferenceCount.h Reference Counting Garbage Collector for C++ @maintainer Morgan McGuire, http://graphics.cs.williams.edu @cite Adapted and extended from Justin Miller's "RGC" class that appeared in BYTE magazine. @cite See also http://www.jelovic.com/articles/cpp_without_memory_errors_slides.htm @created 2001-10-23 @edited 2009-04-25 */ #ifndef G3D_ReferenceCount_h #define G3D_ReferenceCount_h #include "G3D/platform.h" #include "G3D/debug.h" #include "G3D/AtomicInt32.h" namespace G3D { #ifdef _MSC_VER // Turn off "conditional expression is constant" warning; MSVC generates this // for debug assertions in inlined methods. # pragma warning (disable : 4127) #endif /** Base class for WeakReferenceCountedPointer */ class _WeakPtr { public: inline virtual ~_WeakPtr() {} protected: friend class ReferenceCountedObject; /** Called by ReferenceCountedObject to tell a weak pointer that its underlying object was collected. */ virtual void objectCollected() = 0; }; /** Used internally by ReferenceCountedObject */ class _WeakPtrLinkedList { public: _WeakPtr* weakPtr; _WeakPtrLinkedList* next; inline _WeakPtrLinkedList() : weakPtr(NULL), next(NULL) {} /** Inserts this node into the head of the list that previously had n as its head. */ inline _WeakPtrLinkedList(_WeakPtr* p, _WeakPtrLinkedList* n) : weakPtr(p), next(n) {} }; /** Objects that are reference counted inherit from this. Subclasses must have a public destructor (the default destructor is fine) and publicly inherit ReferenceCountedObject. Multiple inheritance from a reference counted object is dangerous-- use at your own risk. ReferenceCountedPointer and ReferenceCountedObject are threadsafe. You can create and drop references on multiple threads without violating integrity. WeakReferenceCountedPointer is not threadsafe. Introducing a weak pointer destroys all thread safety, even for strong pointers to the same object (this is inherent in the design of the class; we cannot fix it without slowing down the performance of reference counted objects.) Usage Example

class Foo : public G3D::ReferenceCountedObject {
public:
    int x;
};

class Bar : public Foo {};

typedef G3D::ReferenceCountedPointer FooRef;
typedef G3D::WeakReferenceCountedPointer WeakFooRef;
typedef G3D::ReferenceCountedPointer BarRef;


int main(int argc, char *argv[]) {

    WeakFooRef x;

    {
        FooRef a = new Foo();

        // Reference count == 1

        x = a;
        // Weak references do not increase count

        {
            FooRef b = a;
            // Reference count == 2
        }

        // Reference count == 1
    }
    // No more strong references; object automatically deleted.
    // x is set to NULL automatically.

    // Example of using dynamic cast on reference counted objects
    BarRef b = new Bar();

    // No cast needed to go down the heirarchy.
    FooRef f = b;

    // We can't cast the reference object because it is a class.
    // Instead we must extract the pointer and cast that:
    b = dynamic_cast(&*f);

    return 0;
}
*/ class ReferenceCountedObject { public: /** The long name is to keep this from accidentally conflicting with a subclass's variable name. Do not use or explicitly manipulate this value--its type may change in the future and is not part of the supported API. */ AtomicInt32 ReferenceCountedObject_refCount; /** Linked list of all weak pointers that reference this (some may be on the stack!). Do not use or explicitly manipulate this value. */ _WeakPtrLinkedList* ReferenceCountedObject_weakPointer; protected: ReferenceCountedObject(); public: /** Automatically called immediately before the object is deleted. This is not called from the destructor because it needs to be invoked before the subclass destructor. */ void ReferenceCountedObject_zeroWeakPointers(); virtual ~ReferenceCountedObject(); /** Note: copies will initially start out with 0 references and 0 weak references like any other object. */ ReferenceCountedObject(const ReferenceCountedObject& notUsed); ReferenceCountedObject& operator=(const ReferenceCountedObject& other); }; /** Use ReferenceCountedPointer in place of T* in your program. T must subclass ReferenceCountedObject. @deprecated To be replaced by boost::shared_ptr in 7.0 */ template class ReferenceCountedPointer { private: T* m_pointer; public: typedef T element_type; inline T* pointer() const { return m_pointer; } private: /** Nulls out the pointer and drops a reference. If the reference count hits zero. */ void zeroPointer() { if (m_pointer != NULL) { ReferenceCountedObject* pointer = ((ReferenceCountedObject*)m_pointer); debugAssert(G3D::isValidHeapPointer(m_pointer)); debugAssertM(pointer->ReferenceCountedObject_refCount.value() > 0, "Dangling reference detected."); // Only delete if this instance caused the count to hit // exactly zero. If there is a race condition, the value // may be zero after decrement returns, but only one of // the instances will get a zero return value. if (pointer->ReferenceCountedObject_refCount.decrement() == 0) { // We held the last reference, so delete the object. // This test is threadsafe because there is no way for // the reference count to increase after the last // reference was dropped (assuming the application does // not voilate the class abstraction). //debugPrintf(" delete 0x%x\n", m_pointer); // We must zero the weak pointers *before* deletion in case there // are cycles of weak references. // Note that since there are no strong references at this point, // it is perfectly fair to zero the weak pointers anyway. pointer->ReferenceCountedObject_zeroWeakPointers(); delete pointer; } m_pointer = NULL; } } /** Non-atomic (except for the referencec increment). Can only be called in contexts like the copy constructor or initial constructor where it is known that the reference count will not hit zero on some other thread. */ void setPointer(T* x) { if (x != m_pointer) { zeroPointer(); if (x != NULL) { debugAssert(G3D::isValidHeapPointer(x)); m_pointer = x; // Note that the ref count can be zero if this is the // first pointer to it ReferenceCountedObject* pointer = (ReferenceCountedObject*)m_pointer; debugAssertM(pointer->ReferenceCountedObject_refCount.value() >= 0, "Negative reference count detected."); pointer->ReferenceCountedObject_refCount.increment(); } } } public: inline ReferenceCountedPointer() : m_pointer(NULL) {} /** Allow silent cast to the base class.
        SubRef  s = new Sub();
        BaseRef b = s;
      
i.e., compile-time subtyping rule RCP<T> <: RCP<S> if T <: S */ template inline ReferenceCountedPointer(const ReferenceCountedPointer& p) : m_pointer(NULL) { setPointer(p.pointer()); } # if (! defined(MSC_VER) || (MSC_VER >= 1300)) /** Explicit cast to a subclass. Acts like dynamic cast; the result will be NULL if the cast cannot succeed. Not supported on VC6.
        SubRef  s = new Sub();
        BaseRef b = s;
        s = b.downcast();   // Note that the template argument is the object type, not the pointer type.
      
*/ template ReferenceCountedPointer downcast() { return ReferenceCountedPointer(dynamic_cast(m_pointer)); } template const ReferenceCountedPointer downcast() const { return ReferenceCountedPointer(dynamic_cast(m_pointer)); } # endif // We need an explicit version of the copy constructor as well or // the default copy constructor will be used. inline ReferenceCountedPointer(const ReferenceCountedPointer& p) : m_pointer(NULL) { setPointer(p.m_pointer); } /** Allows construction from a raw pointer. That object will thereafter be reference counted -- do not call delete on it. Use of const allows downcast on const references */ inline ReferenceCountedPointer(const T* p) : m_pointer(NULL) { // only const constructor is defined to remove ambiguity using NULL setPointer(const_cast(p)); } inline ~ReferenceCountedPointer() { zeroPointer(); } inline size_t hashCode() const { return reinterpret_cast(m_pointer);; } inline const ReferenceCountedPointer& operator=(const ReferenceCountedPointer& p) { setPointer(p.m_pointer); return *this; } inline ReferenceCountedPointer& operator=(T* p) { setPointer(p); return *this; } inline bool operator==(const ReferenceCountedPointer& y) const { return (m_pointer == y.m_pointer); } inline bool operator!=(const ReferenceCountedPointer& y) const { return (m_pointer != y.m_pointer); } bool operator < (const ReferenceCountedPointer& y) const { return (m_pointer < y.m_pointer); } bool operator > (const ReferenceCountedPointer& y) const { return (m_pointer > y.m_pointer); } bool operator <= (const ReferenceCountedPointer& y) const { return (m_pointer <= y.m_pointer); } bool operator >= (const ReferenceCountedPointer& y) const { return (m_pointer >= y.m_pointer); } inline T& operator*() const { debugAssertM(m_pointer != NULL, "Dereferenced a NULL ReferenceCountedPointer"); return (*m_pointer); } inline T* operator->() const { debugAssertM(m_pointer != NULL, "Dereferenced a NULL ReferenceCountedPointer"); return m_pointer; } inline bool isNull() const { return (m_pointer == NULL); } inline bool notNull() const { return (m_pointer != NULL); } // TODO: distinguish between last strong and last any pointer /** Returns true if this is the last reference to an object. Useful for flushing memoization caches-- a cache that holds the last reference is unnecessarily keeping an object alive. Not threadsafe. @deprecated Use WeakReferenceCountedPointer for caches */ inline int isLastReference() const { return (m_pointer->ReferenceCountedObject_refCount.value() == 1); } }; /** A weak pointer allows the object it references to be garbage collected. Weak pointers are commonly used in caches, where it is important to hold a pointer to an object without keeping that object alive solely for the cache's benefit (i.e., the object can be collected as soon as all pointers to it outside the cache are gone). They are also convenient for adding back-pointers in tree and list structures. Weak pointers may become NULL at any point (when their target is collected). Therefore the only way to reference the target is to convert to a strong pointer and then check that it is not NULL. @deprecated To be replaced by boost::weak_ptr in 7.0 */ template class WeakReferenceCountedPointer : public _WeakPtr { private: /** NULL if the object has been collected. */ T* pointer; public: /** Creates a strong pointer, which prevents the object from being garbage collected. The strong pointer may be NULL, which means that the underlying. */ // There is intentionally no way to check if the // WeakReferenceCountedPointer has a null reference without // creating a strong pointer since there is no safe way to use // that information-- the pointer could be collected by a // subsequent statement. ReferenceCountedPointer createStrongPtr() const { // TODO: What if the object's destructor is called while we // are in this method? return ReferenceCountedPointer(pointer); } private: /** Thread issues: safe because this is only called when another object is guaranteed to keep p alive for the duration of this call. */ void setPointer(T* p) { // TODO: must prevent the object from being collected while in // this method zeroPointer(); pointer = p; if (pointer != NULL) { // TODO: threadsafe: must update the list atomically // Add myself to the head of my target's list of weak pointers _WeakPtrLinkedList* head = new _WeakPtrLinkedList (this, pointer->ReferenceCountedObject_weakPointer); pointer->ReferenceCountedObject_weakPointer = head; } else { } } /** Removes this from its target's list of weak pointers. Called when the weak pointer goes out of scope. Thread issues: depends on the thread safety of createStrongPtr. */ void zeroPointer() { // Grab a strong reference to prevent the object from being collected while we // are traversing its list. ReferenceCountedPointer strong = createStrongPtr(); // If the following test fails then the object was collected before we // reached it. if (strong.notNull()) { debugAssertM(((ReferenceCountedObject*)pointer)->ReferenceCountedObject_weakPointer != NULL, "Weak pointer exists without a backpointer from the object."); // Remove myself from my target's list of weak pointers _WeakPtrLinkedList** node = &((ReferenceCountedObject*)pointer)->ReferenceCountedObject_weakPointer; while ((*node)->weakPtr != this) { node = &((*node)->next); debugAssertM(*node != NULL, "Weak pointer exists without a backpointer from the object (2)."); } // Node must now point at the node for me. Remove node and // close the linked list behind it. _WeakPtrLinkedList* temp = *node; *node = temp->next; // Now delete the node corresponding to me delete temp; } pointer = NULL; } public: WeakReferenceCountedPointer() : pointer(0) {} /** Allow compile time subtyping rule RCP<T> <: RCP<S> if T <: S */ template inline WeakReferenceCountedPointer(const WeakReferenceCountedPointer& p) : pointer(0) { // Threadsafe: the object cannot be collected while the other pointer exists. setPointer(p.pointer); } template inline WeakReferenceCountedPointer(const ReferenceCountedPointer& p) : pointer(0) { // Threadsafe: the object cannot be collected while the other // pointer exists. setPointer(p.pointer()); } // Gets called a *lot* when weak pointers are on the stack WeakReferenceCountedPointer( const WeakReferenceCountedPointer& weakPtr) : pointer(0) { setPointer(weakPtr.pointer); } WeakReferenceCountedPointer( const ReferenceCountedPointer& strongPtr) : pointer(0) { setPointer(strongPtr.pointer()); } ~WeakReferenceCountedPointer() { zeroPointer(); } WeakReferenceCountedPointer& operator=(const WeakReferenceCountedPointer& other) { // Threadsafe: the object cannot be collected while the other pointer exists. // I now point at other's target setPointer(other.pointer); return *this; } WeakReferenceCountedPointer& operator=(const ReferenceCountedPointer& other) { // Threadsafe: the object cannot be collected while the other pointer exists. // I now point at other's target setPointer(other.pointer()); return *this; } bool operator==(const WeakReferenceCountedPointer& other) const { return pointer == other.pointer; } bool operator!=(const WeakReferenceCountedPointer& other) const { return pointer != other.pointer; } bool operator < (const WeakReferenceCountedPointer& y) const { return (pointer < y.pointer); } bool operator > (const WeakReferenceCountedPointer& y) const { return (pointer > y.pointer); } bool operator <= (const WeakReferenceCountedPointer& y) const { return (pointer <= y.pointer); } bool operator >= (const ReferenceCountedPointer& y) const { return (pointer >= y.pointer); } protected: /** Invoked by the destructor on ReferenceCountedPointer. */ void objectCollected() { debugAssertM(pointer != NULL, "Removed a weak pointer twice."); pointer = NULL; } }; } // namespace #endif