OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef BASE_MEMORY_REF_COUNTED_H_ | 5 #ifndef BASE_MEMORY_REF_COUNTED_H_ |
6 #define BASE_MEMORY_REF_COUNTED_H_ | 6 #define BASE_MEMORY_REF_COUNTED_H_ |
7 | 7 |
8 #include <stddef.h> | 8 #include <stddef.h> |
9 | 9 |
10 #include <cassert> | 10 #include <cassert> |
11 #include <iosfwd> | 11 #include <iosfwd> |
12 #include <type_traits> | 12 #include <type_traits> |
13 | 13 |
14 #include "base/atomic_ref_count.h" | 14 #include "base/atomic_ref_count.h" |
15 #include "base/base_export.h" | 15 #include "base/base_export.h" |
16 #include "base/compiler_specific.h" | 16 #include "base/compiler_specific.h" |
17 #include "base/logging.h" | 17 #include "base/logging.h" |
18 #include "base/macros.h" | 18 #include "base/macros.h" |
19 #include "base/threading/thread_collision_warner.h" | 19 #include "base/threading/thread_collision_warner.h" |
20 #include "build/build_config.h" | 20 #include "build/build_config.h" |
21 | 21 |
| 22 template <class T> |
| 23 class scoped_refptr; |
| 24 |
22 namespace base { | 25 namespace base { |
23 | 26 |
| 27 template <typename T> |
| 28 scoped_refptr<T> AdoptRef(T* t); |
| 29 |
24 namespace subtle { | 30 namespace subtle { |
25 | 31 |
| 32 enum AdoptRefTag { kAdoptRefTag }; |
| 33 enum StartRefCountFromZeroTag { kStartRefCountFromZeroTag }; |
| 34 enum StartRefCountFromOneTag { kStartRefCountFromOneTag }; |
| 35 |
26 class BASE_EXPORT RefCountedBase { | 36 class BASE_EXPORT RefCountedBase { |
27 public: | 37 public: |
28 bool HasOneRef() const { return ref_count_ == 1; } | 38 bool HasOneRef() const { return ref_count_ == 1; } |
29 | 39 |
30 protected: | 40 protected: |
31 RefCountedBase() {} | 41 explicit RefCountedBase(StartRefCountFromZeroTag) {} |
| 42 explicit RefCountedBase(StartRefCountFromOneTag) : ref_count_(1) { |
| 43 #if DCHECK_IS_ON() |
| 44 needs_adopt_ref_ = true; |
| 45 #endif |
| 46 } |
32 | 47 |
33 ~RefCountedBase() { | 48 ~RefCountedBase() { |
34 #if DCHECK_IS_ON() | 49 #if DCHECK_IS_ON() |
35 DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()"; | 50 DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()"; |
36 #endif | 51 #endif |
37 } | 52 } |
38 | 53 |
39 void AddRef() const { | 54 void AddRef() const { |
40 // TODO(maruel): Add back once it doesn't assert 500 times/sec. | 55 // TODO(maruel): Add back once it doesn't assert 500 times/sec. |
41 // Current thread books the critical section "AddRelease" | 56 // Current thread books the critical section "AddRelease" |
42 // without release it. | 57 // without release it. |
43 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); | 58 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); |
44 #if DCHECK_IS_ON() | 59 #if DCHECK_IS_ON() |
45 DCHECK(!in_dtor_); | 60 DCHECK(!in_dtor_); |
| 61 DCHECK(!needs_adopt_ref_) |
| 62 << "This RefCounted object is created with non-zero reference count." |
| 63 << " The first reference to such a object has to be made by AdoptRef or" |
| 64 << " MakeShared."; |
46 #endif | 65 #endif |
47 | 66 |
48 ++ref_count_; | 67 ++ref_count_; |
49 } | 68 } |
50 | 69 |
51 // Returns true if the object should self-delete. | 70 // Returns true if the object should self-delete. |
52 bool Release() const { | 71 bool Release() const { |
53 --ref_count_; | 72 --ref_count_; |
54 | 73 |
55 // TODO(maruel): Add back once it doesn't assert 500 times/sec. | 74 // TODO(maruel): Add back once it doesn't assert 500 times/sec. |
56 // Current thread books the critical section "AddRelease" | 75 // Current thread books the critical section "AddRelease" |
57 // without release it. | 76 // without release it. |
58 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); | 77 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); |
59 | 78 |
60 #if DCHECK_IS_ON() | 79 #if DCHECK_IS_ON() |
61 DCHECK(!in_dtor_); | 80 DCHECK(!in_dtor_); |
62 if (ref_count_ == 0) | 81 if (ref_count_ == 0) |
63 in_dtor_ = true; | 82 in_dtor_ = true; |
64 #endif | 83 #endif |
65 | 84 |
66 return ref_count_ == 0; | 85 return ref_count_ == 0; |
67 } | 86 } |
68 | 87 |
69 private: | 88 private: |
| 89 template <typename U> |
| 90 friend scoped_refptr<U> base::AdoptRef(U*); |
| 91 |
| 92 void Adopted() const { |
| 93 #if DCHECK_IS_ON() |
| 94 DCHECK(needs_adopt_ref_); |
| 95 needs_adopt_ref_ = false; |
| 96 #endif |
| 97 } |
| 98 |
70 mutable size_t ref_count_ = 0; | 99 mutable size_t ref_count_ = 0; |
| 100 |
71 #if DCHECK_IS_ON() | 101 #if DCHECK_IS_ON() |
| 102 mutable bool needs_adopt_ref_ = false; |
72 mutable bool in_dtor_ = false; | 103 mutable bool in_dtor_ = false; |
73 #endif | 104 #endif |
74 | 105 |
75 DFAKE_MUTEX(add_release_); | 106 DFAKE_MUTEX(add_release_); |
76 | 107 |
77 DISALLOW_COPY_AND_ASSIGN(RefCountedBase); | 108 DISALLOW_COPY_AND_ASSIGN(RefCountedBase); |
78 }; | 109 }; |
79 | 110 |
80 class BASE_EXPORT RefCountedThreadSafeBase { | 111 class BASE_EXPORT RefCountedThreadSafeBase { |
81 public: | 112 public: |
82 bool HasOneRef() const; | 113 bool HasOneRef() const; |
83 | 114 |
84 protected: | 115 protected: |
85 RefCountedThreadSafeBase(); | 116 explicit RefCountedThreadSafeBase(StartRefCountFromZeroTag) {} |
| 117 explicit RefCountedThreadSafeBase(StartRefCountFromOneTag) : ref_count_(1) { |
| 118 #if DCHECK_IS_ON() |
| 119 needs_adopt_ref_ = true; |
| 120 #endif |
| 121 } |
| 122 |
86 ~RefCountedThreadSafeBase(); | 123 ~RefCountedThreadSafeBase(); |
87 | 124 |
88 void AddRef() const; | 125 void AddRef() const; |
89 | 126 |
90 // Returns true if the object should self-delete. | 127 // Returns true if the object should self-delete. |
91 bool Release() const; | 128 bool Release() const; |
92 | 129 |
93 private: | 130 private: |
| 131 template <typename U> |
| 132 friend scoped_refptr<U> base::AdoptRef(U*); |
| 133 |
| 134 void Adopted() const { |
| 135 #if DCHECK_IS_ON() |
| 136 DCHECK(needs_adopt_ref_); |
| 137 needs_adopt_ref_ = false; |
| 138 #endif |
| 139 } |
| 140 |
94 mutable AtomicRefCount ref_count_ = 0; | 141 mutable AtomicRefCount ref_count_ = 0; |
95 #if DCHECK_IS_ON() | 142 #if DCHECK_IS_ON() |
| 143 mutable bool needs_adopt_ref_ = false; |
96 mutable bool in_dtor_ = false; | 144 mutable bool in_dtor_ = false; |
97 #endif | 145 #endif |
98 | 146 |
99 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); | 147 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); |
100 }; | 148 }; |
101 | 149 |
102 } // namespace subtle | 150 } // namespace subtle |
103 | 151 |
104 // | 152 // |
105 // A base class for reference counted classes. Otherwise, known as a cheap | 153 // A base class for reference counted classes. Otherwise, known as a cheap |
106 // knock-off of WebKit's RefCounted<T> class. To use this, just extend your | 154 // knock-off of WebKit's RefCounted<T> class. To use this, just extend your |
107 // class from it like so: | 155 // class from it like so: |
108 // | 156 // |
109 // class MyFoo : public base::RefCounted<MyFoo> { | 157 // class MyFoo : public base::RefCounted<MyFoo> { |
110 // ... | 158 // ... |
111 // private: | 159 // private: |
112 // friend class base::RefCounted<MyFoo>; | 160 // friend class base::RefCounted<MyFoo>; |
113 // ~MyFoo(); | 161 // ~MyFoo(); |
114 // }; | 162 // }; |
115 // | 163 // |
116 // You should always make your destructor non-public, to avoid any code deleting | 164 // You should always make your destructor non-public, to avoid any code deleting |
117 // the object accidently while there are references to it. | 165 // the object accidently while there are references to it. |
118 template <class T> | 166 template <class T> |
119 class RefCounted : public subtle::RefCountedBase { | 167 class RefCounted : public subtle::RefCountedBase { |
120 public: | 168 public: |
121 RefCounted() = default; | 169 static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference = |
| 170 subtle::kStartRefCountFromZeroTag; |
| 171 |
| 172 RefCounted() : subtle::RefCountedBase(T::kRefCountPreference) {} |
122 | 173 |
123 void AddRef() const { | 174 void AddRef() const { |
124 subtle::RefCountedBase::AddRef(); | 175 subtle::RefCountedBase::AddRef(); |
125 } | 176 } |
126 | 177 |
127 void Release() const { | 178 void Release() const { |
128 if (subtle::RefCountedBase::Release()) { | 179 if (subtle::RefCountedBase::Release()) { |
129 delete static_cast<const T*>(this); | 180 delete static_cast<const T*>(this); |
130 } | 181 } |
131 } | 182 } |
132 | 183 |
133 protected: | 184 protected: |
134 ~RefCounted() = default; | 185 ~RefCounted() = default; |
135 | 186 |
136 private: | 187 private: |
137 DISALLOW_COPY_AND_ASSIGN(RefCounted<T>); | 188 DISALLOW_COPY_AND_ASSIGN(RefCounted); |
138 }; | 189 }; |
139 | 190 |
140 // Forward declaration. | 191 // Forward declaration. |
141 template <class T, typename Traits> class RefCountedThreadSafe; | 192 template <class T, typename Traits> class RefCountedThreadSafe; |
142 | 193 |
143 // Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref | 194 // Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref |
144 // count reaches 0. Overload to delete it on a different thread etc. | 195 // count reaches 0. Overload to delete it on a different thread etc. |
145 template<typename T> | 196 template<typename T> |
146 struct DefaultRefCountedThreadSafeTraits { | 197 struct DefaultRefCountedThreadSafeTraits { |
147 static void Destruct(const T* x) { | 198 static void Destruct(const T* x) { |
(...skipping 13 matching lines...) Expand all Loading... |
161 // }; | 212 // }; |
162 // | 213 // |
163 // If you're using the default trait, then you should add compile time | 214 // If you're using the default trait, then you should add compile time |
164 // asserts that no one else is deleting your object. i.e. | 215 // asserts that no one else is deleting your object. i.e. |
165 // private: | 216 // private: |
166 // friend class base::RefCountedThreadSafe<MyFoo>; | 217 // friend class base::RefCountedThreadSafe<MyFoo>; |
167 // ~MyFoo(); | 218 // ~MyFoo(); |
168 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> > | 219 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> > |
169 class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { | 220 class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { |
170 public: | 221 public: |
171 RefCountedThreadSafe() = default; | 222 static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference = |
| 223 subtle::kStartRefCountFromZeroTag; |
| 224 |
| 225 explicit RefCountedThreadSafe() |
| 226 : subtle::RefCountedThreadSafeBase(T::kRefCountPreference) {} |
172 | 227 |
173 void AddRef() const { | 228 void AddRef() const { |
174 subtle::RefCountedThreadSafeBase::AddRef(); | 229 subtle::RefCountedThreadSafeBase::AddRef(); |
175 } | 230 } |
176 | 231 |
177 void Release() const { | 232 void Release() const { |
178 if (subtle::RefCountedThreadSafeBase::Release()) { | 233 if (subtle::RefCountedThreadSafeBase::Release()) { |
179 Traits::Destruct(static_cast<const T*>(this)); | 234 Traits::Destruct(static_cast<const T*>(this)); |
180 } | 235 } |
181 } | 236 } |
(...skipping 19 matching lines...) Expand all Loading... |
201 RefCountedData() : data() {} | 256 RefCountedData() : data() {} |
202 RefCountedData(const T& in_value) : data(in_value) {} | 257 RefCountedData(const T& in_value) : data(in_value) {} |
203 | 258 |
204 T data; | 259 T data; |
205 | 260 |
206 private: | 261 private: |
207 friend class base::RefCountedThreadSafe<base::RefCountedData<T> >; | 262 friend class base::RefCountedThreadSafe<base::RefCountedData<T> >; |
208 ~RefCountedData() = default; | 263 ~RefCountedData() = default; |
209 }; | 264 }; |
210 | 265 |
| 266 // Creates a scoped_refptr from a raw pointer without incrementing the reference |
| 267 // count. Use this only for a newly created object whose reference count starts |
| 268 // from 1 instead of 0. |
| 269 template <typename T> |
| 270 scoped_refptr<T> AdoptRef(T* obj) { |
| 271 using Tag = typename std::decay<decltype(T::kRefCountPreference)>::type; |
| 272 static_assert(std::is_same<subtle::StartRefCountFromOneTag, Tag>::value, |
| 273 "Use AdoptRef only for the reference count starts from one."); |
| 274 |
| 275 DCHECK(obj); |
| 276 DCHECK(obj->HasOneRef()); |
| 277 obj->Adopted(); |
| 278 return scoped_refptr<T>(obj, subtle::kAdoptRefTag); |
| 279 } |
| 280 |
| 281 namespace subtle { |
| 282 |
| 283 template <typename T> |
| 284 scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromZeroTag) { |
| 285 return scoped_refptr<T>(obj); |
| 286 } |
| 287 |
| 288 template <typename T> |
| 289 scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromOneTag) { |
| 290 return AdoptRef(obj); |
| 291 return scoped_refptr<T>(obj); |
| 292 } |
| 293 |
| 294 } // namespace subtle |
| 295 |
| 296 // Constructs an instance of T, which is a ref counted type, and wraps the |
| 297 // object into a scoped_refptr. |
| 298 template <typename T, typename... Args> |
| 299 scoped_refptr<T> MakeShared(Args&&... args) { |
| 300 T* obj = new T(std::forward<Args>(args)...); |
| 301 return subtle::AdoptRefIfNeeded(obj, T::kRefCountPreference); |
| 302 } |
| 303 |
211 } // namespace base | 304 } // namespace base |
212 | 305 |
213 // | 306 // |
214 // A smart pointer class for reference counted objects. Use this class instead | 307 // A smart pointer class for reference counted objects. Use this class instead |
215 // of calling AddRef and Release manually on a reference counted object to | 308 // of calling AddRef and Release manually on a reference counted object to |
216 // avoid common memory leaks caused by forgetting to Release an object | 309 // avoid common memory leaks caused by forgetting to Release an object |
217 // reference. Sample usage: | 310 // reference. Sample usage: |
218 // | 311 // |
219 // class MyFoo : public RefCounted<MyFoo> { | 312 // class MyFoo : public RefCounted<MyFoo> { |
220 // ... | 313 // ... |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
368 | 461 |
369 template <typename U> | 462 template <typename U> |
370 bool operator<(const scoped_refptr<U>& rhs) const { | 463 bool operator<(const scoped_refptr<U>& rhs) const { |
371 return ptr_ < rhs.get(); | 464 return ptr_ < rhs.get(); |
372 } | 465 } |
373 | 466 |
374 protected: | 467 protected: |
375 T* ptr_ = nullptr; | 468 T* ptr_ = nullptr; |
376 | 469 |
377 private: | 470 private: |
| 471 template <typename U> |
| 472 friend scoped_refptr<U> base::AdoptRef(U*); |
| 473 |
| 474 scoped_refptr(T* p, base::subtle::AdoptRefTag) : ptr_(p) {} |
| 475 |
378 // Friend required for move constructors that set r.ptr_ to null. | 476 // Friend required for move constructors that set r.ptr_ to null. |
379 template <typename U> | 477 template <typename U> |
380 friend class scoped_refptr; | 478 friend class scoped_refptr; |
381 | 479 |
382 // Non-inline helpers to allow: | 480 // Non-inline helpers to allow: |
383 // class Opaque; | 481 // class Opaque; |
384 // extern template class scoped_refptr<Opaque>; | 482 // extern template class scoped_refptr<Opaque>; |
385 // Otherwise the compiler will complain that Opaque is an incomplete type. | 483 // Otherwise the compiler will complain that Opaque is an incomplete type. |
386 static void AddRef(T* ptr); | 484 static void AddRef(T* ptr); |
387 static void Release(T* ptr); | 485 static void Release(T* ptr); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
445 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { | 543 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { |
446 return !operator==(null, rhs); | 544 return !operator==(null, rhs); |
447 } | 545 } |
448 | 546 |
449 template <typename T> | 547 template <typename T> |
450 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { | 548 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { |
451 return out << p.get(); | 549 return out << p.get(); |
452 } | 550 } |
453 | 551 |
454 #endif // BASE_MEMORY_REF_COUNTED_H_ | 552 #endif // BASE_MEMORY_REF_COUNTED_H_ |
OLD | NEW |