Class linked_ptr

Synopsis

#include <include/EASTL/linked_ptr.h>

template <typename T, typename Deleter = smart_ptr_deleter<T> >
class linked_ptr : public linked_ptr_base

Description

linked_ptr

This class implements a linked_ptr template. A linked_ptr is like the C++ Standard Library auto_ptr except that it allows sharing of pointers between instances of auto_ptr via reference counting. linked_ptr objects can safely be copied and can safely be used in C++ Standard Library containers such as std::vector or std::list. This implementation, however, is not thread-safe. you would need to use a separate linked_ptr_mt (multi-threaded) to get thread safety.

linked_ptr is a variation of shared_ptr (a.k.a. counted_ptr) which differs in that instead of being implemented by a shared integer stored on the heap, it is implemented by linked list stored within the linked_ptr object itself. The result is that no memory is explicitly allocated from the heap, though the cost of each linked_ptr object is 12 bytes of memory (32 bit machine) instead of 4 bytes for the case of shared_ptr (depending on the heap).

Mentioned in

Inheritance

Ancestors: linked_ptr_base

Methods

linked_ptr overloadlinked_ptr Default constructor.
linked_ptr overloadlinked_ptr Takes ownership of the pointer
linked_ptr overloadlinked_ptr Construction with self type
linked_ptr overloadlinked_ptr Shares ownership of a pointer with another instance of linked_ptr.
~linked_ptr~linked_ptr Removes this object from the of objects using the shared pointer
detachdetach Returns ownership of the pointer to the caller
force_deleteforce_delete Forces deletion of the shared pointer
getget Returns the owned pointer
operator bool_
operator!operator! This returns the opposite of operator bool; it returns true if the owned pointer is null
operator*swap Exchanges the owned pointer beween two linkedPtr objects.
operator->operator-> Allows access to the owned pointer via operator->()
operator= overloadoperator= If we want a shared_ptr operator= that is templated on linked_ptr, then we need to make it in addition to this function, as otherwise the compiler will generate this function and things will go wrong.
operator= overloadoperator= Copies another linked_ptr to this object
operator= overloadoperator= Assigns a new pointer
reset overloadreset Releases the owned pointer and takes ownership of the passed in pointer
reset overloadreset Resets the container with NULL
uniqueunique Returns true if the use count of the owned pointer is one
use_countuse_count Returns the use count of the shared pointer

Source

Lines 54-359 in include/EASTL/linked_ptr.h.

template <typename T, typename Deleter = smart_ptr_deleter<T> >
class linked_ptr : public linked_ptr_base
{
protected:
    template <typename U, typename D> friend class linked_ptr;
    /// this_type
    /// This is an alias for linked_ptr<T>, this class.
    typedef linked_ptr<T> this_type;
    /// deleter_type
    typedef Deleter deleter_type;
    T* mpValue; /// The owned pointer.
    template <typename U, typename D>
    void link(const linked_ptr<U, D>& linkedPtr)
    {   // This code can only be called when we are in a reset state.
        // assert(!mpValue && (mpNext == mpPrev));
        mpNext           = linkedPtr.mpNext;
        mpNext->mpPrev   = this;
        mpPrev           = const_cast<linked_ptr<U, D>*>(&linkedPtr);
        linkedPtr.mpNext = this;
    }
public:
    /// element_type
    /// Synonym for type T, useful for external code to reference the 
    /// type in a generic way.
    typedef T element_type;
    /// linked_ptr
    /// Default constructor.
    linked_ptr() 
        : mpValue(NULL)
    {
        mpPrev = mpNext = this;
    }
    /// linked_ptr
    /// Takes ownership of the pointer. It is OK if the input pointer is null.
    template <typename U>
    explicit linked_ptr(U* pValue) 
        : mpValue(pValue)
    {
        mpPrev = mpNext = this;
    }
    /// linked_ptr
    /// Construction with self type.
    /// If we want a shared_ptr constructor that is templated on linked_ptr<U>,
    /// then we need to make it in addition to this function, as otherwise 
    /// the compiler will generate this function and things will go wrong.
    linked_ptr(const linked_ptr& linkedPtr)
        : mpValue(linkedPtr.mpValue)
    {
        if(mpValue)
            link(linkedPtr);
        else
            mpPrev = mpNext = this;
    }
    /// linked_ptr
    /// Shares ownership of a pointer with another instance of linked_ptr.
    template <typename U, typename D>
    linked_ptr(const linked_ptr<U, D>& linkedPtr)
        : mpValue(linkedPtr.mpValue)
    {
        if(mpValue)
            link(linkedPtr);
        else
            mpPrev = mpNext = this;
    }
    /// ~linked_ptr
    /// Removes this object from the of objects using the shared pointer.
    /// If this object is the last owner of the shared pointer, the shared 
    /// pointer is deleted.
    ~linked_ptr() 
    {
        reset();
    }
    /// operator=
    /// If we want a shared_ptr operator= that is templated on linked_ptr<U>,
    /// then we need to make it in addition to this function, as otherwise 
    /// the compiler will generate this function and things will go wrong.
    linked_ptr& operator=(const linked_ptr& linkedPtr)
    {
        if(linkedPtr.mpValue != mpValue)
        {
            reset(linkedPtr.mpValue);
            if(linkedPtr.mpValue)
                link(linkedPtr);
        }
        return *this;
    }
    /// operator=
    /// Copies another linked_ptr to this object. Note that this object
    /// may already own a shared pointer with another different pointer
    /// (but still of the same type) before this call. In that case,
    /// this function removes ownership of the old pointer and takes shared 
    /// ownership of the new pointer and increments its reference count.
    template <typename U, typename D>
    linked_ptr& operator=(const linked_ptr<U, D>& linkedPtr)
    {
        if(linkedPtr.mpValue != mpValue)
        {
            reset(linkedPtr.mpValue);
            if(linkedPtr.mpValue)
                link(linkedPtr);
        }
        return *this;
    }
    /// operator=
    /// Assigns a new pointer. If the new pointer is equivalent
    /// to the current pointer, nothing is done. Otherwise the 
    /// current pointer is unlinked and possibly destroyed.
    /// The new pointer can be NULL.
    template <typename U>
    linked_ptr& operator=(U* pValue)
    {
        reset(pValue);
        return *this;
    }
    /// reset
    /// Releases the owned pointer and takes ownership of the 
    /// passed in pointer. If the passed in pointer is the same
    /// as the owned pointer, nothing is done. The passed in pointer
    /// can be NULL, in which case the use count is set to 1.
    template <typename U>
    void reset(U* pValue)
    {
        if(pValue != mpValue)
        {
            if(unique())
            {
                deleter_type del;
                del(mpValue);
            }
            else
            {
                mpPrev->mpNext  = mpNext;
                mpNext->mpPrev  = mpPrev;
                mpPrev = mpNext = this;
            }
            mpValue = pValue;
        }
    }
    /// reset
    /// Resets the container with NULL. If the current pointer
    /// is non-NULL, it is unlinked and possibly destroyed.
    void reset()
    {
        reset((T*)NULL);
    }
    /// swap
    /// Exchanges the owned pointer beween two linkedPtr objects.
    ///
    /// This function is disabled as it is currently deemed unsafe.
    /// The problem is that the only way to implement this function
    /// is to transfer pointers between the objects; you cannot 
    /// transfer the linked list membership between the objects. 
    /// Thus unless both linked_ptr objects were 'unique()', the 
    /// shared pointers would be duplicated amongst containers, 
    /// resulting in a crash.
    //template <typename U, typename D>
    //void swap(linked_ptr<U, D>& linkedPtr)
    //{
    //    if(linkedPtr.mpValue != mpValue)
    //    {   // This is only safe if both linked_ptrs are unique().
    //        linkedPtr::element_type* const pValueTemp = linkedPtr.mpValue;
    //        linkedPtr.reset(mpValue);
    //        reset(pValueTemp);
    //    }
    //}
    /// operator*
    /// Returns the owner pointer dereferenced.
    T& operator*() const
    {
        return *mpValue;
    }
    /// operator->
    /// Allows access to the owned pointer via operator->()
    T* operator->() const
    {
        return mpValue;
    }
    /// get
    /// Returns the owned pointer. Note that this class does 
    /// not provide an operator T() function. This is because such
    /// a thing (automatic conversion) is deemed unsafe.
    T* get() const
    {
        return mpValue;
    }
    /// use_count
    /// Returns the use count of the shared pointer.
    /// The return value is one if the owned pointer is null.
    /// This function is provided for compatibility with the 
    /// proposed C++ standard and for debugging purposes. It is not
    /// intended for runtime use given that its execution time is
    /// not constant.
    int use_count() const
    {
        int useCount(1);

        for(const linked_ptr_base* pCurrent = static_cast<const linked_ptr_base*>(this); 
                pCurrent->mpNext != static_cast<const linked_ptr_base*>(this); pCurrent = pCurrent->mpNext)
            ++useCount;
        return useCount;
    }
    /// unique
    /// Returns true if the use count of the owned pointer is one.
    /// The return value is true if the owned pointer is null.
    bool unique() const
    {
        return (mpNext == static_cast<const linked_ptr_base*>(this));
    }
    /// Implicit operator bool
    /// Allows for using a linked_ptr as a boolean. 
    /// Note that below we do not use operator bool(). The reason for this
    /// is that booleans automatically convert up to short, int, float, etc.
    /// The result is that this: if(linkedPtr == 1) would yield true (bad).
    typedef T* (this_type::*bool_)() const;
    operator bool_() const
    {
        if(mpValue)
            return &this_type::get;
        return NULL;
    }
    /// operator!
    /// This returns the opposite of operator bool; it returns true if 
    /// the owned pointer is null. Some compilers require this and some don't.
    bool operator!()
    {
        return (mpValue == NULL);
    }
    /// detach
    /// Returns ownership of the pointer to the caller.  Fixes all
    /// references to the pointer by any other owners to be NULL.
    /// This function can work properly only if all entries in the list 
    /// refer to type T and none refer to any other type (e.g. U).
    T* detach()
    {
        T* const pValue = mpValue;
        linked_ptr_base* p = this;
        do
        {
            linked_ptr_base* const pNext = p->mpNext;
            static_cast<this_type*>(p)->mpValue = NULL;
            p->mpNext = p->mpPrev = p;
            p = pNext;
        }
        while(p != this);
        return pValue;
    }
    /// force_delete
    /// Forces deletion of the shared pointer. Fixes all references to the 
    /// pointer by any other owners to be NULL.
    /// This function can work properly only if all entries in the list 
    /// refer to type T and none refer to any other type (e.g. U).
    void force_delete()
    {
        T* const pValue = detach();
        Deleter del;
        del(pValue);
    }
}; // class linked_ptr





Add Discussion as Guest

Log in