|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ |
|
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 public: |
|
65 ~nsTWeakRef() { |
|
66 if (mRef) |
|
67 mRef->Release(); |
|
68 } |
|
69 |
|
70 /** |
|
71 * Construct from an object pointer (may be null). |
|
72 */ |
|
73 explicit |
|
74 nsTWeakRef(Type *obj = nullptr) { |
|
75 if (obj) { |
|
76 mRef = new Inner(obj); |
|
77 } else { |
|
78 mRef = nullptr; |
|
79 } |
|
80 } |
|
81 |
|
82 /** |
|
83 * Construct from another weak reference object. |
|
84 */ |
|
85 explicit |
|
86 nsTWeakRef(const nsTWeakRef<Type> &other) : mRef(other.mRef) { |
|
87 if (mRef) |
|
88 mRef->AddRef(); |
|
89 } |
|
90 |
|
91 /** |
|
92 * Assign from an object pointer. |
|
93 */ |
|
94 nsTWeakRef<Type> &operator=(Type *obj) { |
|
95 if (mRef) |
|
96 mRef->Release(); |
|
97 if (obj) { |
|
98 mRef = new Inner(obj); |
|
99 } else { |
|
100 mRef = nullptr; |
|
101 } |
|
102 return *this; |
|
103 } |
|
104 |
|
105 /** |
|
106 * Assign from another weak reference object. |
|
107 */ |
|
108 nsTWeakRef<Type> &operator=(const nsTWeakRef<Type> &other) { |
|
109 if (mRef) |
|
110 mRef->Release(); |
|
111 mRef = other.mRef; |
|
112 if (mRef) |
|
113 mRef->AddRef(); |
|
114 return *this; |
|
115 } |
|
116 |
|
117 /** |
|
118 * Get the referenced object. This method may return null if the reference |
|
119 * has been cleared or if an out-of-memory error occurred at assignment. |
|
120 */ |
|
121 Type *get() const { |
|
122 return mRef ? mRef->mObj : nullptr; |
|
123 } |
|
124 |
|
125 /** |
|
126 * Called to "null out" the weak reference. Typically, the object referenced |
|
127 * by this weak reference calls this method when it is being destroyed. |
|
128 * @returns The former referenced object. |
|
129 */ |
|
130 Type *forget() { |
|
131 Type *obj; |
|
132 if (mRef) { |
|
133 obj = mRef->mObj; |
|
134 mRef->mObj = nullptr; |
|
135 mRef->Release(); |
|
136 mRef = nullptr; |
|
137 } else { |
|
138 obj = nullptr; |
|
139 } |
|
140 return obj; |
|
141 } |
|
142 |
|
143 /** |
|
144 * Allow |*this| to be treated as a |Type*| for convenience. |
|
145 */ |
|
146 operator Type *() const { |
|
147 return get(); |
|
148 } |
|
149 |
|
150 /** |
|
151 * Allow |*this| to be treated as a |Type*| for convenience. Use with |
|
152 * caution since this method will crash if the referenced object is null. |
|
153 */ |
|
154 Type *operator->() const { |
|
155 NS_ASSERTION(mRef && mRef->mObj, |
|
156 "You can't dereference a null weak reference with operator->()."); |
|
157 return get(); |
|
158 } |
|
159 |
|
160 private: |
|
161 |
|
162 struct Inner { |
|
163 int mCnt; |
|
164 Type *mObj; |
|
165 |
|
166 Inner(Type *obj) : mCnt(1), mObj(obj) {} |
|
167 void AddRef() { ++mCnt; } |
|
168 void Release() { if (--mCnt == 0) delete this; } |
|
169 }; |
|
170 |
|
171 Inner *mRef; |
|
172 }; |
|
173 |
|
174 #endif // nsTWeakRef_h__ |