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 #ifndef nsTWeakRef_h__ 8 #define nsTWeakRef_h__ 9 10 #ifndef nsDebug_h___ 11 #include "nsDebug.h" 12 #endif 13 14 /** 15 * A weak reference class for use with generic C++ objects. NOT THREADSAFE! 16 * 17 * Example usage: 18 * 19 * class A { 20 * public: 21 * A() : mWeakSelf(this) { 22 * } 23 * ~A() { 24 * mWeakSelf.forget(); 25 * } 26 * void Bar() { printf("Bar!\n"); } 27 * const nsTWeakRef<A> &AsWeakRef() const { return mWeakSelf; } 28 * private: 29 * nsTWeakRef<A> mWeakSelf; 30 * }; 31 * 32 * class B { 33 * public: 34 * void SetA(const nsTWeakRef<A> &a) { 35 * mA = a; 36 * } 37 * void Foo() { 38 * if (mA) 39 * mA->Bar(); 40 * } 41 * private: 42 * nsTWeakRef<A> mA; 43 * }; 44 * 45 * void Test() { 46 * B b; 47 * { 48 * A a; 49 * b.SetA(a.AsWeakRef()); 50 * b.Foo(); // prints "Bar!" 51 * } 52 * b.Foo(); // prints nothing because |a| has already been destroyed 53 * } 54 * 55 * One can imagine much more complex examples, especially when asynchronous 56 * event processing is involved. 57 * 58 * Keep in mind that you should only ever need a class like this when you have 59 * multiple instances of B, such that it is not possible for A and B to simply 60 * have pointers to one another. 61 */ 62 template<class Type> 63 class nsTWeakRef 64 { 65 public: ~nsTWeakRef()66 ~nsTWeakRef() 67 {} 68 69 /** 70 * Construct from an object pointer (may be null). 71 */ 72 explicit nsTWeakRef(Type* aObj = nullptr) 73 { 74 if (aObj) { 75 mRef = new Inner(aObj); 76 } else { 77 mRef = nullptr; 78 } 79 } 80 81 /** 82 * Construct from another weak reference object. 83 */ nsTWeakRef(const nsTWeakRef<Type> & aOther)84 explicit nsTWeakRef(const nsTWeakRef<Type>& aOther) : mRef(aOther.mRef) 85 {} 86 87 /** 88 * Assign from an object pointer. 89 */ 90 nsTWeakRef<Type>& operator=(Type* aObj) 91 { 92 if (aObj) { 93 mRef = new Inner(aObj); 94 } else { 95 mRef = nullptr; 96 } 97 return *this; 98 } 99 100 /** 101 * Assign from another weak reference object. 102 */ 103 nsTWeakRef<Type>& operator=(const nsTWeakRef<Type>& aOther) 104 { 105 mRef = aOther.mRef; 106 return *this; 107 } 108 109 /** 110 * Get the referenced object. This method may return null if the reference 111 * has been cleared or if an out-of-memory error occurred at assignment. 112 */ get()113 Type* get() const { return mRef ? mRef->mObj : nullptr; } 114 115 /** 116 * Called to "null out" the weak reference. Typically, the object referenced 117 * by this weak reference calls this method when it is being destroyed. 118 * @returns The former referenced object. 119 */ forget()120 Type* forget() 121 { 122 Type* obj; 123 if (mRef) { 124 obj = mRef->mObj; 125 mRef->mObj = nullptr; 126 mRef = nullptr; 127 } else { 128 obj = nullptr; 129 } 130 return obj; 131 } 132 133 /** 134 * Allow |*this| to be treated as a |Type*| for convenience. 135 */ 136 operator Type*() const { return get(); } 137 138 /** 139 * Allow |*this| to be treated as a |Type*| for convenience. Use with 140 * caution since this method will crash if the referenced object is null. 141 */ 142 Type* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN 143 { 144 NS_ASSERTION(mRef && mRef->mObj, 145 "You can't dereference a null weak reference with operator->()."); 146 return get(); 147 } 148 149 private: 150 151 struct Inner 152 { 153 int mCnt; 154 Type* mObj; 155 InnerInner156 explicit Inner(Type* aObj) 157 : mCnt(1) 158 , mObj(aObj) 159 { 160 } AddRefInner161 void AddRef() 162 { 163 ++mCnt; 164 } ReleaseInner165 void Release() 166 { 167 if (--mCnt == 0) { 168 delete this; 169 } 170 } 171 }; 172 173 RefPtr<Inner> mRef; 174 }; 175 176 #endif // nsTWeakRef_h__ 177