[haiku-development] BWeakReferenceable

Hi,

found Axel's nice WeakReferenceable implementation but had some problems 
to understand how to use it. For example, the management of the 
WeakPointer ref counting and the conversion into a WeakReference was a 
bit confusing to me. I attached a new API which is more similar to 
BReference and hopefully easier to use.

In this new API you don't store a WeakPointer but a BWeakReference. The 
BWeakReference allows no direct access to the actual object but you can 
try to convert it into a BReference. If this attempt succeed you can 
use the BReference to access the object safely.

See the attached small example program to make it more clear *)

Think this is the standard way how weak pointers work in other 
frameworks.

Furthermore, BWeakReferenceable has a virtual destructor now, Axel is 
that a problem in your net server code?

Opinions?

thanks,
        Clemens


*)

class Test : public BWeakReferenceable {
public:
        ~Test()
        {
                printf("~Test\n");
        }
};


int
main()
{
        BReference<Test> ref;
        ref.SetTo(new Test, true);

        // store a weak ref of the object
        BWeakReference<Test> weakRef = ref.Get();

        // try to convert the weakRef into a stronRef, this works because 
the Test object is still alive
        BReference<Test> strongRef = weakRef.GetReference();
        printf("strongRef %p\n", strongRef.Get());
        strongRef = NULL;
        // release the last reference to the Test object
        ref = NULL;

        // now it fails to get a strong pointer because the Test object 
died
        strongRef = weakRef.GetReference();
        printf("strongRef %p\n", strongRef.Get());

        return 0;
}


Output:

strongRef 0x18019170
~Test
strongRef (nil)


/*
 * Copyright 2009, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx
 * Distributed under the terms of the MIT License.
 */
#ifndef _WEAK_REFERENCEABLE_H
#define _WEAK_REFERENCEABLE_H


#include <Referenceable.h>


namespace BPrivate {


class BWeakReferenceable;


class WeakPointer : public BReferenceable {
public:
                                                                
WeakPointer(BWeakReferenceable* object);
                                                                ~WeakPointer();

                        BWeakReferenceable*     Get();
                        bool                            Put();

                        int32                           UseCount() const;

                        void                            GetUnchecked();

private:
                        vint32                          fUseCount;
                        BWeakReferenceable*     fObject;
};


template<typename Type> class BWeakReference;


class BWeakReferenceable {
public:
                                                                
BWeakReferenceable();
        virtual                                         ~BWeakReferenceable();

                        void                            AcquireReference()
                                                                        { 
fPointer->GetUnchecked(); }

                        bool                            ReleaseReference()
                                                                        { 
return fPointer->Put(); }

                        int32                           CountReferences() const
                                                                        { 
return fPointer->UseCount(); }

                        WeakPointer*            GetWeakPointer();
private:
                        WeakPointer*            fPointer;
};


template<typename Type>
class BWeakReference {
public:
        BWeakReference()
                :
                fPointer(NULL)
        {
        }

        BWeakReference(BWeakReferenceable* object)
                :
                fPointer(NULL)
        {
                SetTo(object);
        }

        BWeakReference(const BWeakReference<Type>& other)
                :
                fPointer(NULL)
        {
                SetTo(other);
        }

        ~BWeakReference()
        {
                Unset();
        }

        void SetTo(BWeakReferenceable* object)
        {
                Unset();

                if (object != NULL)
                        fPointer = object->GetWeakPointer();
        }

        void SetTo(const BWeakReference<Type>& other)
        {
                Unset();

                if (other.fPointer) {
                        fPointer = other.fPointer;
                        fPointer->AcquireReference();
                }
        }

        void Unset()
        {
                if (fPointer != NULL) {
                        fPointer->ReleaseReference();
                        fPointer = NULL;
                }
        }

        BReference<Type>
        GetReference()
        {
                Type* object = static_cast<Type*>(fPointer->Get());
                return BReference<Type>(object, true);
        }

        BWeakReference& operator=(const BWeakReference<Type>& other)
        {
                if (this == &other)
                        return *this;

                SetTo(other.fPointer);
                return *this;
        }

        BWeakReference& operator=(const Type& other)
        {
                SetTo(&other);
                return *this;
        }

        bool operator==(const BWeakReference<Type>& other) const
        {
                return fPointer == other.fPointer;
        }

        bool operator!=(const BWeakReference<Type>& other) const
        {
                return fPointer != other.fPointer;
        }

private:
        WeakPointer*    fPointer;
};


//      #pragma mark -


inline
WeakPointer::WeakPointer(BWeakReferenceable* object)
        :
        fUseCount(1),
        fObject(object)
{
}


inline
WeakPointer::~WeakPointer()
{
}


inline BWeakReferenceable*
WeakPointer::Get()
{
        int32 count = -11;

        do {
                count = atomic_get(&fUseCount);
                if (count == 0)
                        return NULL;
        } while (atomic_test_and_set(&fUseCount, count + 1, count) != count);

        return fObject;
}


inline bool
WeakPointer::Put()
{
        if (atomic_add(&fUseCount, -1) == 1) {
                delete fObject;
                return true;
        }

        return false;
}


inline int32
WeakPointer::UseCount() const
{
        return fUseCount;
}


inline void
WeakPointer::GetUnchecked()
{
        atomic_add(&fUseCount, 1);
}


//      #pragma -


inline
BWeakReferenceable::BWeakReferenceable()
        :
        fPointer(new WeakPointer(this))
{
}


inline
BWeakReferenceable::~BWeakReferenceable()
{
        fPointer->ReleaseReference();
}


inline WeakPointer*
BWeakReferenceable::GetWeakPointer()
{
        fPointer->AcquireReference();
        return fPointer;
}

}       // namespace BPrivate

using BPrivate::BWeakReferenceable;
using BPrivate::BWeakReference;

#endif  // _WEAK_REFERENCEABLE_H

Other related posts: