1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* Weak pointer functionality, implemented as a mixin for use with any class. */ 8 9 /** 10 * SupportsWeakPtr lets you have a pointer to an object 'Foo' without affecting 11 * its lifetime. It works by creating a single shared reference counted object 12 * (WeakReference) that each WeakPtr will access 'Foo' through. This lets 'Foo' 13 * clear the pointer in the WeakReference without having to know about all of 14 * the WeakPtrs to it and allows the WeakReference to live beyond the lifetime 15 * of 'Foo'. 16 * 17 * PLEASE NOTE: This weak pointer implementation is not thread-safe. 18 * 19 * Note that when deriving from SupportsWeakPtr you should add 20 * MOZ_DECLARE_WEAKREFERENCE_TYPENAME(ClassName) to the public section of your 21 * class, where ClassName is the name of your class. 22 * 23 * The overhead of WeakPtr is that accesses to 'Foo' becomes an additional 24 * dereference, and an additional heap allocated pointer sized object shared 25 * between all of the WeakPtrs. 26 * 27 * Example of usage: 28 * 29 * // To have a class C support weak pointers, inherit from 30 * // SupportsWeakPtr<C>. 31 * class C : public SupportsWeakPtr<C> 32 * { 33 * public: 34 * MOZ_DECLARE_WEAKREFERENCE_TYPENAME(C) 35 * int mNum; 36 * void act(); 37 * }; 38 * 39 * C* ptr = new C(); 40 * 41 * // Get weak pointers to ptr. The first time a weak pointer 42 * // is obtained, a reference counted WeakReference object is created that 43 * // can live beyond the lifetime of 'ptr'. The WeakReference 44 * // object will be notified of 'ptr's destruction. 45 * WeakPtr<C> weak = ptr; 46 * WeakPtr<C> other = ptr; 47 * 48 * // Test a weak pointer for validity before using it. 49 * if (weak) { 50 * weak->mNum = 17; 51 * weak->act(); 52 * } 53 * 54 * // Destroying the underlying object clears weak pointers to it. 55 * delete ptr; 56 * 57 * MOZ_ASSERT(!weak, "Deleting |ptr| clears weak pointers to it."); 58 * MOZ_ASSERT(!other, "Deleting |ptr| clears all weak pointers to it."); 59 * 60 * WeakPtr is typesafe and may be used with any class. It is not required that 61 * the class be reference-counted or allocated in any particular way. 62 * 63 * The API was loosely inspired by Chromium's weak_ptr.h: 64 * http://src.chromium.org/svn/trunk/src/base/memory/weak_ptr.h 65 */ 66 67 #ifndef mozilla_WeakPtr_h 68 #define mozilla_WeakPtr_h 69 70 #include "mozilla/ArrayUtils.h" 71 #include "mozilla/Assertions.h" 72 #include "mozilla/Attributes.h" 73 #include "mozilla/RefCounted.h" 74 #include "mozilla/RefPtr.h" 75 #include "mozilla/TypeTraits.h" 76 77 #include <string.h> 78 79 namespace mozilla { 80 81 template <typename T> class WeakPtr; 82 template <typename T> class SupportsWeakPtr; 83 84 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING 85 #define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T) \ 86 static const char* weakReferenceTypeName() { return "WeakReference<" #T ">"; } 87 #else 88 #define MOZ_DECLARE_WEAKREFERENCE_TYPENAME(T) 89 #endif 90 91 namespace detail { 92 93 // This can live beyond the lifetime of the class derived from 94 // SupportsWeakPtr. 95 template<class T> 96 class WeakReference : public ::mozilla::RefCounted<WeakReference<T> > 97 { 98 public: WeakReference(T * p)99 explicit WeakReference(T* p) : mPtr(p) {} 100 get()101 T* get() const { return mPtr; } 102 103 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING typeName()104 const char* typeName() const 105 { 106 // The first time this is called mPtr is null, so don't 107 // invoke any methods on mPtr. 108 return T::weakReferenceTypeName(); 109 } typeSize()110 size_t typeSize() const { return sizeof(*this); } 111 #endif 112 113 private: 114 friend class mozilla::SupportsWeakPtr<T>; 115 detach()116 void detach() { mPtr = nullptr; } 117 118 T* MOZ_NON_OWNING_REF mPtr; 119 }; 120 121 } // namespace detail 122 123 template <typename T> 124 class SupportsWeakPtr 125 { 126 protected: ~SupportsWeakPtr()127 ~SupportsWeakPtr() 128 { 129 static_assert(IsBaseOf<SupportsWeakPtr<T>, T>::value, 130 "T must derive from SupportsWeakPtr<T>"); 131 if (mSelfReferencingWeakPtr) { 132 mSelfReferencingWeakPtr.mRef->detach(); 133 } 134 } 135 136 private: SelfReferencingWeakPtr()137 const WeakPtr<T>& SelfReferencingWeakPtr() 138 { 139 if (!mSelfReferencingWeakPtr) { 140 mSelfReferencingWeakPtr.mRef = new detail::WeakReference<T>(static_cast<T*>(this)); 141 } 142 return mSelfReferencingWeakPtr; 143 } 144 SelfReferencingWeakPtr()145 const WeakPtr<const T>& SelfReferencingWeakPtr() const 146 { 147 const WeakPtr<T>& p = const_cast<SupportsWeakPtr*>(this)->SelfReferencingWeakPtr(); 148 return reinterpret_cast<const WeakPtr<const T>&>(p); 149 } 150 151 friend class WeakPtr<T>; 152 friend class WeakPtr<const T>; 153 154 WeakPtr<T> mSelfReferencingWeakPtr; 155 }; 156 157 template <typename T> 158 class WeakPtr 159 { 160 typedef detail::WeakReference<T> WeakReference; 161 162 public: 163 WeakPtr& operator=(const WeakPtr& aOther) 164 { 165 mRef = aOther.mRef; 166 return *this; 167 } 168 WeakPtr(const WeakPtr & aOther)169 WeakPtr(const WeakPtr& aOther) 170 { 171 *this = aOther; 172 } 173 174 WeakPtr& operator=(T* aOther) 175 { 176 if (aOther) { 177 *this = aOther->SelfReferencingWeakPtr(); 178 } else if (!mRef || mRef->get()) { 179 // Ensure that mRef is dereferenceable in the uninitialized state. 180 mRef = new WeakReference(nullptr); 181 } 182 return *this; 183 } 184 WeakPtr(T * aOther)185 MOZ_IMPLICIT WeakPtr(T* aOther) 186 { 187 *this = aOther; 188 } 189 190 // Ensure that mRef is dereferenceable in the uninitialized state. WeakPtr()191 WeakPtr() : mRef(new WeakReference(nullptr)) {} 192 193 operator T*() const { return mRef->get(); } 194 T& operator*() const { return *mRef->get(); } 195 196 T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { return mRef->get(); } 197 get()198 T* get() const { return mRef->get(); } 199 200 private: 201 friend class SupportsWeakPtr<T>; 202 WeakPtr(const RefPtr<WeakReference> & aOther)203 explicit WeakPtr(const RefPtr<WeakReference>& aOther) : mRef(aOther) {} 204 205 RefPtr<WeakReference> mRef; 206 }; 207 208 } // namespace mozilla 209 210 #endif /* mozilla_WeakPtr_h */ 211