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 | |
26 class BASE_EXPORT RefCountedBase { | 34 class BASE_EXPORT RefCountedBase { |
27 public: | 35 public: |
28 bool HasOneRef() const { return ref_count_ == 1; } | 36 bool HasOneRef() const { return ref_count_ == 1; } |
29 | 37 |
30 protected: | 38 protected: |
31 RefCountedBase() | 39 explicit RefCountedBase(size_t initial_ref_count = 0) |
dcheng
2017/03/30 04:26:15
I think I would prefer that we have a default ctor
| |
32 : ref_count_(0) | 40 : ref_count_(initial_ref_count) { |
33 #if DCHECK_IS_ON() | 41 #if DCHECK_IS_ON() |
34 , in_dtor_(false) | 42 DCHECK(initial_ref_count == 0 || initial_ref_count == 1); |
43 needs_adopt_ref_ = ref_count_ == 1; | |
35 #endif | 44 #endif |
36 { | |
37 } | 45 } |
38 | 46 |
39 ~RefCountedBase() { | 47 ~RefCountedBase() { |
40 #if DCHECK_IS_ON() | 48 #if DCHECK_IS_ON() |
41 DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()"; | 49 DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()"; |
42 #endif | 50 #endif |
43 } | 51 } |
44 | 52 |
45 | |
46 void AddRef() const { | 53 void AddRef() const { |
47 // TODO(maruel): Add back once it doesn't assert 500 times/sec. | 54 // TODO(maruel): Add back once it doesn't assert 500 times/sec. |
48 // Current thread books the critical section "AddRelease" | 55 // Current thread books the critical section "AddRelease" |
49 // without release it. | 56 // without release it. |
50 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); | 57 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); |
51 #if DCHECK_IS_ON() | 58 #if DCHECK_IS_ON() |
52 DCHECK(!in_dtor_); | 59 DCHECK(!in_dtor_); |
60 DCHECK(!needs_adopt_ref_) | |
61 << "This RefCounted object is created with non-zero reference count." | |
62 << " The first reference to such a object has to be made by AdoptRef or" | |
63 << " MakeShared."; | |
53 #endif | 64 #endif |
65 | |
54 ++ref_count_; | 66 ++ref_count_; |
55 } | 67 } |
56 | 68 |
57 // Returns true if the object should self-delete. | 69 // Returns true if the object should self-delete. |
58 bool Release() const { | 70 bool Release() const { |
71 --ref_count_; | |
72 | |
59 // TODO(maruel): Add back once it doesn't assert 500 times/sec. | 73 // TODO(maruel): Add back once it doesn't assert 500 times/sec. |
60 // Current thread books the critical section "AddRelease" | 74 // Current thread books the critical section "AddRelease" |
61 // without release it. | 75 // without release it. |
62 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); | 76 // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); |
77 | |
63 #if DCHECK_IS_ON() | 78 #if DCHECK_IS_ON() |
64 DCHECK(!in_dtor_); | 79 DCHECK(!in_dtor_); |
65 #endif | 80 if (ref_count_ == 0) |
66 if (--ref_count_ == 0) { | |
67 #if DCHECK_IS_ON() | |
68 in_dtor_ = true; | 81 in_dtor_ = true; |
69 #endif | 82 #endif |
70 return true; | 83 |
71 } | 84 return ref_count_ == 0; |
dcheng
2017/03/30 04:26:15
What is the purpose / necessity for these changes?
tzik
2017/03/30 13:16:27
Oops, this is a contamination from another CL: htt
| |
72 return false; | |
73 } | 85 } |
74 | 86 |
75 private: | 87 private: |
88 template <typename U> | |
89 friend scoped_refptr<U> base::AdoptRef(U*); | |
90 | |
91 void Adopted() const { | |
92 #if DCHECK_IS_ON() | |
93 DCHECK(needs_adopt_ref_); | |
94 needs_adopt_ref_ = false; | |
95 #endif | |
96 } | |
97 | |
76 mutable size_t ref_count_; | 98 mutable size_t ref_count_; |
99 | |
77 #if DCHECK_IS_ON() | 100 #if DCHECK_IS_ON() |
78 mutable bool in_dtor_; | 101 mutable bool needs_adopt_ref_; |
102 mutable bool in_dtor_ = false; | |
79 #endif | 103 #endif |
80 | 104 |
81 DFAKE_MUTEX(add_release_); | 105 DFAKE_MUTEX(add_release_); |
82 | 106 |
83 DISALLOW_COPY_AND_ASSIGN(RefCountedBase); | 107 DISALLOW_COPY_AND_ASSIGN(RefCountedBase); |
84 }; | 108 }; |
85 | 109 |
86 class BASE_EXPORT RefCountedThreadSafeBase { | 110 class BASE_EXPORT RefCountedThreadSafeBase { |
87 public: | 111 public: |
88 bool HasOneRef() const; | 112 bool HasOneRef() const; |
89 | 113 |
90 protected: | 114 protected: |
91 RefCountedThreadSafeBase(); | 115 explicit RefCountedThreadSafeBase(AtomicRefCount initial_ref_count = 0) |
116 : ref_count_(initial_ref_count) { | |
117 #if DCHECK_IS_ON() | |
118 needs_adopt_ref_ = initial_ref_count == 1; | |
119 #endif | |
120 } | |
121 | |
92 ~RefCountedThreadSafeBase(); | 122 ~RefCountedThreadSafeBase(); |
93 | 123 |
94 void AddRef() const; | 124 void AddRef() const; |
95 | 125 |
96 // Returns true if the object should self-delete. | 126 // Returns true if the object should self-delete. |
97 bool Release() const; | 127 bool Release() const; |
98 | 128 |
99 private: | 129 private: |
100 mutable AtomicRefCount ref_count_ = 0; | 130 template <typename U> |
131 friend scoped_refptr<U> base::AdoptRef(U*); | |
132 | |
133 void Adopted() const { | |
101 #if DCHECK_IS_ON() | 134 #if DCHECK_IS_ON() |
135 DCHECK(needs_adopt_ref_); | |
136 needs_adopt_ref_ = false; | |
137 #endif | |
138 } | |
139 | |
140 mutable AtomicRefCount ref_count_; | |
141 #if DCHECK_IS_ON() | |
142 mutable bool needs_adopt_ref_; | |
102 mutable bool in_dtor_ = false; | 143 mutable bool in_dtor_ = false; |
103 #endif | 144 #endif |
104 | 145 |
105 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); | 146 DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase); |
106 }; | 147 }; |
107 | 148 |
108 } // namespace subtle | 149 } // namespace subtle |
109 | 150 |
110 // | 151 // |
111 // A base class for reference counted classes. Otherwise, known as a cheap | 152 // A base class for reference counted classes. Otherwise, known as a cheap |
112 // knock-off of WebKit's RefCounted<T> class. To use this, just extend your | 153 // knock-off of WebKit's RefCounted<T> class. To use this, just extend your |
113 // class from it like so: | 154 // class from it like so: |
114 // | 155 // |
115 // class MyFoo : public base::RefCounted<MyFoo> { | 156 // class MyFoo : public base::RefCounted<MyFoo> { |
116 // ... | 157 // ... |
117 // private: | 158 // private: |
118 // friend class base::RefCounted<MyFoo>; | 159 // friend class base::RefCounted<MyFoo>; |
119 // ~MyFoo(); | 160 // ~MyFoo(); |
120 // }; | 161 // }; |
121 // | 162 // |
122 // You should always make your destructor non-public, to avoid any code deleting | 163 // You should always make your destructor non-public, to avoid any code deleting |
123 // the object accidently while there are references to it. | 164 // the object accidently while there are references to it. |
124 template <class T> | 165 template <class T> |
125 class RefCounted : public subtle::RefCountedBase { | 166 class RefCounted : public subtle::RefCountedBase { |
126 public: | 167 public: |
127 RefCounted() = default; | 168 explicit RefCounted(size_t initial_ref_count = 0) |
169 : subtle::RefCountedBase(initial_ref_count) {} | |
128 | 170 |
129 void AddRef() const { | 171 void AddRef() const { |
130 subtle::RefCountedBase::AddRef(); | 172 subtle::RefCountedBase::AddRef(); |
131 } | 173 } |
132 | 174 |
133 void Release() const { | 175 void Release() const { |
134 if (subtle::RefCountedBase::Release()) { | 176 if (subtle::RefCountedBase::Release()) { |
135 delete static_cast<const T*>(this); | 177 delete static_cast<const T*>(this); |
136 } | 178 } |
137 } | 179 } |
(...skipping 29 matching lines...) Expand all Loading... | |
167 // }; | 209 // }; |
168 // | 210 // |
169 // If you're using the default trait, then you should add compile time | 211 // If you're using the default trait, then you should add compile time |
170 // asserts that no one else is deleting your object. i.e. | 212 // asserts that no one else is deleting your object. i.e. |
171 // private: | 213 // private: |
172 // friend class base::RefCountedThreadSafe<MyFoo>; | 214 // friend class base::RefCountedThreadSafe<MyFoo>; |
173 // ~MyFoo(); | 215 // ~MyFoo(); |
174 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> > | 216 template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> > |
175 class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { | 217 class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { |
176 public: | 218 public: |
177 RefCountedThreadSafe() = default; | 219 explicit RefCountedThreadSafe(AtomicRefCount initial_ref_count = 0) |
220 : subtle::RefCountedThreadSafeBase(initial_ref_count) {} | |
178 | 221 |
179 void AddRef() const { | 222 void AddRef() const { |
180 subtle::RefCountedThreadSafeBase::AddRef(); | 223 subtle::RefCountedThreadSafeBase::AddRef(); |
181 } | 224 } |
182 | 225 |
183 void Release() const { | 226 void Release() const { |
184 if (subtle::RefCountedThreadSafeBase::Release()) { | 227 if (subtle::RefCountedThreadSafeBase::Release()) { |
185 Traits::Destruct(static_cast<const T*>(this)); | 228 Traits::Destruct(static_cast<const T*>(this)); |
186 } | 229 } |
187 } | 230 } |
(...skipping 19 matching lines...) Expand all Loading... | |
207 RefCountedData() : data() {} | 250 RefCountedData() : data() {} |
208 RefCountedData(const T& in_value) : data(in_value) {} | 251 RefCountedData(const T& in_value) : data(in_value) {} |
209 | 252 |
210 T data; | 253 T data; |
211 | 254 |
212 private: | 255 private: |
213 friend class base::RefCountedThreadSafe<base::RefCountedData<T> >; | 256 friend class base::RefCountedThreadSafe<base::RefCountedData<T> >; |
214 ~RefCountedData() = default; | 257 ~RefCountedData() = default; |
215 }; | 258 }; |
216 | 259 |
260 // Creates a scoped_refptr from a raw pointer without incrementing the reference | |
261 // count. Use this only for a newly created object whose reference count starts | |
262 // from 1 instead of 0. | |
263 template <typename T> | |
264 scoped_refptr<T> AdoptRef(T* t) { | |
265 DCHECK(!t || t->HasOneRef()); | |
dcheng
2017/03/30 04:26:16
Hmm... why would we want to handle a null |t| here
tzik
2017/03/30 13:16:27
OK, updated to force nun-null.
| |
266 if (t) | |
267 t->Adopted(); | |
268 return scoped_refptr<T>(t, subtle::kAdoptRefTag); | |
269 } | |
270 | |
271 // Constructs an instance of T, which is a ref counted type, and wraps the | |
272 // object into a scoped_refptr. | |
273 template <typename T, typename... Args> | |
274 scoped_refptr<T> MakeShared(Args&&... args) { | |
275 T* obj = new T(std::forward<Args>(args)...); | |
276 if (obj->HasOneRef()) | |
277 return AdoptRef(obj); | |
278 return scoped_refptr<T>(obj); | |
dcheng
2017/03/30 04:26:16
Not sure if it's possible, but it would be nice if
tzik
2017/03/30 13:16:27
Trying that.
| |
279 } | |
280 | |
217 } // namespace base | 281 } // namespace base |
218 | 282 |
219 // | 283 // |
220 // A smart pointer class for reference counted objects. Use this class instead | 284 // A smart pointer class for reference counted objects. Use this class instead |
221 // of calling AddRef and Release manually on a reference counted object to | 285 // of calling AddRef and Release manually on a reference counted object to |
222 // avoid common memory leaks caused by forgetting to Release an object | 286 // avoid common memory leaks caused by forgetting to Release an object |
223 // reference. Sample usage: | 287 // reference. Sample usage: |
224 // | 288 // |
225 // class MyFoo : public RefCounted<MyFoo> { | 289 // class MyFoo : public RefCounted<MyFoo> { |
226 // ... | 290 // ... |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
374 | 438 |
375 template <typename U> | 439 template <typename U> |
376 bool operator<(const scoped_refptr<U>& rhs) const { | 440 bool operator<(const scoped_refptr<U>& rhs) const { |
377 return ptr_ < rhs.get(); | 441 return ptr_ < rhs.get(); |
378 } | 442 } |
379 | 443 |
380 protected: | 444 protected: |
381 T* ptr_ = nullptr; | 445 T* ptr_ = nullptr; |
382 | 446 |
383 private: | 447 private: |
448 template <typename U> | |
449 friend scoped_refptr<U> base::AdoptRef(U*); | |
450 | |
451 scoped_refptr(T* p, base::subtle::AdoptRefTag) : ptr_(p) {} | |
452 | |
384 // Friend required for move constructors that set r.ptr_ to null. | 453 // Friend required for move constructors that set r.ptr_ to null. |
385 template <typename U> | 454 template <typename U> |
386 friend class scoped_refptr; | 455 friend class scoped_refptr; |
387 | 456 |
388 // Non-inline helpers to allow: | 457 // Non-inline helpers to allow: |
389 // class Opaque; | 458 // class Opaque; |
390 // extern template class scoped_refptr<Opaque>; | 459 // extern template class scoped_refptr<Opaque>; |
391 // Otherwise the compiler will complain that Opaque is an incomplete type. | 460 // Otherwise the compiler will complain that Opaque is an incomplete type. |
392 static void AddRef(T* ptr); | 461 static void AddRef(T* ptr); |
393 static void Release(T* ptr); | 462 static void Release(T* ptr); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
451 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { | 520 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) { |
452 return !operator==(null, rhs); | 521 return !operator==(null, rhs); |
453 } | 522 } |
454 | 523 |
455 template <typename T> | 524 template <typename T> |
456 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { | 525 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) { |
457 return out << p.get(); | 526 return out << p.get(); |
458 } | 527 } |
459 | 528 |
460 #endif // BASE_MEMORY_REF_COUNTED_H_ | 529 #endif // BASE_MEMORY_REF_COUNTED_H_ |
OLD | NEW |