1 // LAF Base Library 2 // Copyright (c) 2001-2016 David Capello 3 // 4 // This file is released under the terms of the MIT license. 5 // Read LICENSE.txt for more information. 6 7 #ifndef BASE_SHARED_PTR_H_INCLUDED 8 #define BASE_SHARED_PTR_H_INCLUDED 9 #pragma once 10 11 #include "base/debug.h" 12 13 namespace base { 14 15 // This class counts references for a SharedPtr. 16 class SharedPtrRefCounterBase { 17 public: SharedPtrRefCounterBase()18 SharedPtrRefCounterBase() : m_count(0) { } ~SharedPtrRefCounterBase()19 virtual ~SharedPtrRefCounterBase() { } 20 add_ref()21 void add_ref() { 22 ++m_count; 23 } 24 release()25 void release() { 26 --m_count; 27 if (m_count == 0) 28 delete this; 29 } 30 use_count()31 long use_count() const { 32 return m_count; 33 } 34 35 private: 36 long m_count; // Number of references. 37 }; 38 39 // Default deleter used by shared pointer (it calls "delete" 40 // operator). 41 template<class T> 42 class DefaultSharedPtrDeleter { 43 public: operator()44 void operator()(T* ptr) { 45 delete ptr; 46 } 47 }; 48 49 // A reference counter with a custom deleter. 50 template<class T, class Deleter> 51 class SharedPtrRefCounterImpl : public SharedPtrRefCounterBase { 52 public: SharedPtrRefCounterImpl(T * ptr,Deleter deleter)53 SharedPtrRefCounterImpl(T* ptr, Deleter deleter) 54 : m_ptr(ptr) 55 , m_deleter(deleter) { 56 } 57 ~SharedPtrRefCounterImpl()58 ~SharedPtrRefCounterImpl() { 59 if (m_ptr) 60 m_deleter(m_ptr); 61 } 62 63 private: 64 T* m_ptr; 65 Deleter m_deleter; // Used to destroy the pointer. 66 }; 67 68 // Wraps a pointer and keeps reference counting to automatically 69 // delete the pointed object when it is no longer used. 70 template<class T> 71 class SharedPtr { 72 public: 73 typedef T element_type; 74 SharedPtr()75 SharedPtr() 76 : m_ptr(nullptr) 77 , m_refCount(nullptr) 78 { 79 } 80 81 // Constructor with default deleter. SharedPtr(T * ptr)82 explicit SharedPtr(T* ptr) 83 { 84 create_refcount(ptr, DefaultSharedPtrDeleter<T>()); 85 m_ptr = ptr; 86 add_ref(); 87 } 88 89 // Constructor with customized deleter. 90 template<class Deleter> SharedPtr(T * ptr,Deleter deleter)91 SharedPtr(T* ptr, Deleter deleter) 92 { 93 create_refcount(ptr, deleter); 94 m_ptr = ptr; 95 add_ref(); 96 } 97 98 // Copy other pointer SharedPtr(const SharedPtr<T> & other)99 SharedPtr(const SharedPtr<T>& other) 100 : m_ptr(other.m_ptr) 101 , m_refCount(other.m_refCount) 102 { 103 add_ref(); 104 } 105 106 // Copy other pointer (of static_casteable type) 107 template<class Y> SharedPtr(const SharedPtr<Y> & other)108 SharedPtr(const SharedPtr<Y>& other) 109 : m_ptr(static_cast<T*>(const_cast<Y*>(other.m_ptr))) 110 , m_refCount(const_cast<SharedPtrRefCounterBase*>(other.m_refCount)) 111 { 112 add_ref(); 113 } 114 115 // Releases one reference from the pointee. ~SharedPtr()116 virtual ~SharedPtr() 117 { 118 release(); 119 } 120 121 void reset(T* ptr = nullptr) 122 { 123 if (m_ptr != ptr) { 124 release(); 125 m_ptr = nullptr; 126 m_refCount = nullptr; 127 128 if (ptr) { 129 create_refcount(ptr, DefaultSharedPtrDeleter<T>()); 130 m_ptr = ptr; 131 add_ref(); 132 } 133 } 134 } 135 136 template<class Deleter> reset(T * ptr,Deleter deleter)137 void reset(T* ptr, Deleter deleter) 138 { 139 if (m_ptr != ptr) { 140 release(); 141 m_ptr = nullptr; 142 m_refCount = nullptr; 143 144 if (ptr) { 145 create_refcount(ptr, deleter); 146 m_ptr = ptr; 147 add_ref(); 148 } 149 } 150 } 151 152 SharedPtr& operator=(const SharedPtr<T>& other) 153 { 154 if (m_ptr != other.m_ptr) { 155 release(); 156 m_ptr = other.m_ptr; 157 m_refCount = other.m_refCount; 158 add_ref(); 159 } 160 return *this; 161 } 162 163 template<class Y> 164 SharedPtr& operator=(const SharedPtr<Y>& other) 165 { 166 if (m_ptr != static_cast<T*>(other.m_ptr)) { 167 release(); 168 m_ptr = static_cast<T*>(const_cast<Y*>(other.m_ptr)); 169 m_refCount = const_cast<SharedPtrRefCounterBase*>(other.m_refCount); 170 add_ref(); 171 } 172 return *this; 173 } 174 get()175 T* get() const { return m_ptr; } 176 T& operator*() const { return *m_ptr; } 177 T* operator->() const { return m_ptr; } 178 explicit operator bool() const { return (m_ptr != nullptr); } 179 use_count()180 long use_count() const { return (m_refCount ? m_refCount->use_count(): 0); } unique()181 bool unique() const { return use_count() == 1; } 182 183 private: 184 185 template<typename Deleter> create_refcount(T * ptr,Deleter deleter)186 void create_refcount(T* ptr, Deleter deleter) { 187 if (ptr) { 188 try { 189 m_refCount = new SharedPtrRefCounterImpl<T, Deleter>(ptr, deleter); 190 } 191 catch (...) { 192 if (ptr) 193 deleter(ptr); 194 throw; 195 } 196 } 197 else 198 m_refCount = nullptr; 199 } 200 201 // Adds a reference to the pointee. add_ref()202 void add_ref() 203 { 204 if (m_refCount) 205 m_refCount->add_ref(); 206 207 ASSERT((m_refCount && m_ptr) || (!m_refCount && !m_ptr)); 208 } 209 210 // Removes the reference to the pointee. release()211 void release() 212 { 213 if (m_refCount) 214 m_refCount->release(); 215 216 ASSERT((m_refCount && m_ptr) || (!m_refCount && !m_ptr)); 217 } 218 219 T* m_ptr; // The pointee object. 220 SharedPtrRefCounterBase* m_refCount; // Number of references. 221 222 template<class> friend class SharedPtr; 223 }; 224 225 // Compares if two shared-pointers points to the same place (object, 226 // memory address). 227 template<class T> 228 bool operator==(const SharedPtr<T>& ptr1, const SharedPtr<T>& ptr2) 229 { 230 return ptr1.get() == ptr2.get(); 231 } 232 233 // Compares if two shared-pointers points to different places 234 // (objects, memory addresses). 235 template<class T> 236 bool operator!=(const SharedPtr<T>& ptr1, const SharedPtr<T>& ptr2) 237 { 238 return ptr1.get() != ptr2.get(); 239 } 240 241 } // namespace base 242 243 #endif 244