// ASE base library // Copyright (C) 2001-2012 David Capello // // This source file is ditributed under a BSD-like license, please // read LICENSE.txt for more information. #ifndef BASE_SHARED_PTR_H_INCLUDED #define BASE_SHARED_PTR_H_INCLUDED // This class counts references for a SharedPtr. class SharedPtrRefCounterBase { public: SharedPtrRefCounterBase() : m_count(0) { } virtual ~SharedPtrRefCounterBase() { } void add_ref() { ++m_count; } void release() { --m_count; if (m_count == 0) delete this; } long use_count() const { return m_count; } private: long m_count; // Number of references. }; // Default deleter used by shared pointer (it calls "delete" // operator). template class DefaultSharedPtrDeleter { public: void operator()(T* ptr) { delete ptr; } }; // A reference counter with a custom deleter. template class SharedPtrRefCounterImpl : public SharedPtrRefCounterBase { public: SharedPtrRefCounterImpl(T* ptr, Deleter deleter) : m_ptr(ptr) , m_deleter(deleter) { } ~SharedPtrRefCounterImpl() { m_deleter(m_ptr); } private: T* m_ptr; Deleter m_deleter; // Used to destroy the pointer. }; // Wraps a pointer and keeps reference counting to automatically // delete the pointed object when it is no longer used. template class SharedPtr { public: typedef T element_type; SharedPtr() : m_ptr(0) , m_refCount(0) { } // Constructor with default deleter. explicit SharedPtr(T* ptr) { try { m_refCount = new SharedPtrRefCounterImpl >(ptr, DefaultSharedPtrDeleter()); } catch (...) { DefaultSharedPtrDeleter()(ptr); throw; } m_ptr = ptr; add_ref(); } // Constructor with customized deleter. template SharedPtr(T* ptr, Deleter deleter) { try { m_refCount = new SharedPtrRefCounterImpl(ptr, deleter); } catch (...) { deleter(ptr); throw; } m_ptr = ptr; add_ref(); } // Copy other pointer SharedPtr(const SharedPtr& other) : m_ptr(other.m_ptr) , m_refCount(other.m_refCount) { add_ref(); } // Copy other pointer (of static_casteable type) template SharedPtr(const SharedPtr& other) : m_ptr(static_cast(const_cast(other.m_ptr))) , m_refCount(const_cast(other.m_refCount)) { add_ref(); } // Releases one reference from the pointee. virtual ~SharedPtr() { release(); } void reset(T* ptr = 0) { if (m_ptr != ptr) { release(); m_ptr = 0; m_refCount = 0; if (ptr) { try { m_refCount = new SharedPtrRefCounterImpl >(ptr, DefaultSharedPtrDeleter()); } catch (...) { DefaultSharedPtrDeleter()(ptr); throw; } m_ptr = ptr; add_ref(); } } } template void reset(T* ptr, Deleter deleter) { if (m_ptr != ptr) { release(); m_ptr = 0; m_refCount = 0; if (ptr) { try { m_refCount = new SharedPtrRefCounterImpl(ptr, deleter); } catch (...) { deleter(ptr); throw; } m_ptr = ptr; add_ref(); } } } SharedPtr& operator=(const SharedPtr& other) { if (m_ptr != other.m_ptr) { release(); m_ptr = other.m_ptr; m_refCount = other.m_refCount; add_ref(); } return *this; } template SharedPtr& operator=(const SharedPtr& other) { if (m_ptr != static_cast(other.m_ptr)) { release(); m_ptr = static_cast(const_cast(other.m_ptr)); m_refCount = const_cast(other.m_refCount); add_ref(); } return *this; } T* get() const { return m_ptr; } T& operator*() const { return *m_ptr; } T* operator->() const { return m_ptr; } operator T*() const { return m_ptr; } long use_count() const { return (m_refCount ? m_refCount->use_count(): 0); } bool unique() const { return use_count() == 1; } private: // Adds a reference to the pointee. void add_ref() { if (m_refCount) m_refCount->add_ref(); } // Removes the reference to the pointee. void release() { if (m_refCount) m_refCount->release(); } T* m_ptr; // The pointee object. SharedPtrRefCounterBase* m_refCount; // Number of references. template friend class SharedPtr; }; // Compares if two shared-pointers points to the same place (object, // memory address). template bool operator==(const SharedPtr& ptr1, const SharedPtr& ptr2) { return ptr1.get() == ptr2.get(); } // Compares if two shared-pointers points to different places // (objects, memory addresses). template bool operator!=(const SharedPtr& ptr1, const SharedPtr& ptr2) { return ptr1.get() != ptr2.get(); } #endif