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
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
- Design / Smart Pointer Design
- FAQ / EASTL coverage of std STL
- FAQ / Perf.1 How efficient is EASTL compared to standard C++ STL implementations?
- Glossary / EASTL Glossary
- Modules / Module List
Inheritance
Ancestors: linked_ptr_base
Methods
linked_ptr overload | linked_ptr Default constructor. | |
linked_ptr overload | linked_ptr Takes ownership of the pointer | |
linked_ptr overload | linked_ptr Construction with self type | |
linked_ptr overload | linked_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 | |
detach | detach Returns ownership of the pointer to the caller | |
force_delete | force_delete Forces deletion of the shared pointer | |
get | get Returns the owned pointer | |
link | 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= overload | operator= 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= overload | operator= Copies another linked_ptr to this object | |
operator= overload | operator= Assigns a new pointer | |
reset overload | reset Releases the owned pointer and takes ownership of the passed in pointer | |
reset overload | reset Resets the container with NULL | |
unique | unique Returns true if the use count of the owned pointer is one | |
use_count | use_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