• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_MEMORY_SCOPED_REFPTR_H_
6 #define BASE_MEMORY_SCOPED_REFPTR_H_
7 
8 #include <stddef.h>
9 
10 #include <iosfwd>
11 #include <type_traits>
12 #include <utility>
13 
14 #include "base/check.h"
15 #include "base/compiler_specific.h"
16 #include "base/memory/raw_ptr_exclusion.h"
17 
18 template <class T>
19 class scoped_refptr;
20 
21 namespace base {
22 
23 template <class, typename>
24 class RefCounted;
25 template <class, typename>
26 class RefCountedThreadSafe;
27 template <class>
28 class RefCountedDeleteOnSequence;
29 class SequencedTaskRunner;
30 
31 template <typename T>
32 scoped_refptr<T> AdoptRef(T* t);
33 
34 namespace subtle {
35 
36 enum AdoptRefTag { kAdoptRefTag };
37 enum StartRefCountFromZeroTag { kStartRefCountFromZeroTag };
38 enum StartRefCountFromOneTag { kStartRefCountFromOneTag };
39 
40 template <typename TagType>
41 struct RefCountPreferenceTagTraits;
42 
43 template <>
44 struct RefCountPreferenceTagTraits<StartRefCountFromZeroTag> {
45   static constexpr StartRefCountFromZeroTag kTag = kStartRefCountFromZeroTag;
46 };
47 
48 template <>
49 struct RefCountPreferenceTagTraits<StartRefCountFromOneTag> {
50   static constexpr StartRefCountFromOneTag kTag = kStartRefCountFromOneTag;
51 };
52 
53 template <typename T, typename Tag = typename T::RefCountPreferenceTag>
54 constexpr Tag GetRefCountPreference() {
55   return RefCountPreferenceTagTraits<Tag>::kTag;
56 }
57 
58 // scoped_refptr<T> is typically used with one of several RefCounted<T> base
59 // classes or with custom AddRef and Release methods. These overloads dispatch
60 // on which was used.
61 
62 template <typename T, typename U, typename V>
63 constexpr bool IsRefCountPreferenceOverridden(const T*,
64                                               const RefCounted<U, V>*) {
65   return !std::is_same_v<std::decay_t<decltype(GetRefCountPreference<T>())>,
66                          std::decay_t<decltype(GetRefCountPreference<U>())>>;
67 }
68 
69 template <typename T, typename U, typename V>
70 constexpr bool IsRefCountPreferenceOverridden(
71     const T*,
72     const RefCountedThreadSafe<U, V>*) {
73   return !std::is_same_v<std::decay_t<decltype(GetRefCountPreference<T>())>,
74                          std::decay_t<decltype(GetRefCountPreference<U>())>>;
75 }
76 
77 template <typename T, typename U>
78 constexpr bool IsRefCountPreferenceOverridden(
79     const T*,
80     const RefCountedDeleteOnSequence<U>*) {
81   return !std::is_same_v<std::decay_t<decltype(GetRefCountPreference<T>())>,
82                          std::decay_t<decltype(GetRefCountPreference<U>())>>;
83 }
84 
85 constexpr bool IsRefCountPreferenceOverridden(...) {
86   return false;
87 }
88 
89 template <typename T, typename U, typename V>
90 constexpr void AssertRefCountBaseMatches(const T*, const RefCounted<U, V>*) {
91   static_assert(std::is_base_of_v<U, T>,
92                 "T implements RefCounted<U>, but U is not a base of T.");
93 }
94 
95 template <typename T, typename U, typename V>
96 constexpr void AssertRefCountBaseMatches(const T*,
97                                          const RefCountedThreadSafe<U, V>*) {
98   static_assert(
99       std::is_base_of_v<U, T>,
100       "T implements RefCountedThreadSafe<U>, but U is not a base of T.");
101 }
102 
103 template <typename T, typename U>
104 constexpr void AssertRefCountBaseMatches(const T*,
105                                          const RefCountedDeleteOnSequence<U>*) {
106   static_assert(
107       std::is_base_of_v<U, T>,
108       "T implements RefCountedDeleteOnSequence<U>, but U is not a base of T.");
109 }
110 
111 constexpr void AssertRefCountBaseMatches(...) {}
112 
113 }  // namespace subtle
114 
115 // Creates a scoped_refptr from a raw pointer without incrementing the reference
116 // count. Use this only for a newly created object whose reference count starts
117 // from 1 instead of 0.
118 template <typename T>
119 scoped_refptr<T> AdoptRef(T* obj) {
120   using Tag = std::decay_t<decltype(subtle::GetRefCountPreference<T>())>;
121   static_assert(std::is_same_v<subtle::StartRefCountFromOneTag, Tag>,
122                 "Use AdoptRef only if the reference count starts from one.");
123 
124   DCHECK(obj);
125   DCHECK(obj->HasOneRef());
126   obj->Adopted();
127   return scoped_refptr<T>(obj, subtle::kAdoptRefTag);
128 }
129 
130 namespace subtle {
131 
132 template <typename T>
133 scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromZeroTag) {
134   return scoped_refptr<T>(obj);
135 }
136 
137 template <typename T>
138 scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromOneTag) {
139   return AdoptRef(obj);
140 }
141 
142 }  // namespace subtle
143 
144 // Constructs an instance of T, which is a ref counted type, and wraps the
145 // object into a scoped_refptr<T>.
146 template <typename T, typename... Args>
147 scoped_refptr<T> MakeRefCounted(Args&&... args) {
148   T* obj = new T(std::forward<Args>(args)...);
149   return subtle::AdoptRefIfNeeded(obj, subtle::GetRefCountPreference<T>());
150 }
151 
152 // Takes an instance of T, which is a ref counted type, and wraps the object
153 // into a scoped_refptr<T>.
154 template <typename T>
155 scoped_refptr<T> WrapRefCounted(T* t) {
156   return scoped_refptr<T>(t);
157 }
158 
159 }  // namespace base
160 
161 //
162 // A smart pointer class for reference counted objects.  Use this class instead
163 // of calling AddRef and Release manually on a reference counted object to
164 // avoid common memory leaks caused by forgetting to Release an object
165 // reference.  Sample usage:
166 //
167 //   class MyFoo : public RefCounted<MyFoo> {
168 //    ...
169 //    private:
170 //     friend class RefCounted<MyFoo>;  // Allow destruction by RefCounted<>.
171 //     ~MyFoo();                        // Destructor must be private/protected.
172 //   };
173 //
174 //   void some_function() {
175 //     scoped_refptr<MyFoo> foo = MakeRefCounted<MyFoo>();
176 //     foo->Method(param);
177 //     // |foo| is released when this function returns
178 //   }
179 //
180 //   void some_other_function() {
181 //     scoped_refptr<MyFoo> foo = MakeRefCounted<MyFoo>();
182 //     ...
183 //     foo.reset();  // explicitly releases |foo|
184 //     ...
185 //     if (foo)
186 //       foo->Method(param);
187 //   }
188 //
189 // The above examples show how scoped_refptr<T> acts like a pointer to T.
190 // Given two scoped_refptr<T> classes, it is also possible to exchange
191 // references between the two objects, like so:
192 //
193 //   {
194 //     scoped_refptr<MyFoo> a = MakeRefCounted<MyFoo>();
195 //     scoped_refptr<MyFoo> b;
196 //
197 //     b.swap(a);
198 //     // now, |b| references the MyFoo object, and |a| references nullptr.
199 //   }
200 //
201 // To make both |a| and |b| in the above example reference the same MyFoo
202 // object, simply use the assignment operator:
203 //
204 //   {
205 //     scoped_refptr<MyFoo> a = MakeRefCounted<MyFoo>();
206 //     scoped_refptr<MyFoo> b;
207 //
208 //     b = a;
209 //     // now, |a| and |b| each own a reference to the same MyFoo object.
210 //   }
211 //
212 // Also see Chromium's ownership and calling conventions:
213 // https://chromium.googlesource.com/chromium/src/+/lkgr/styleguide/c++/c++.md#object-ownership-and-calling-conventions
214 // Specifically:
215 //   If the function (at least sometimes) takes a ref on a refcounted object,
216 //   declare the param as scoped_refptr<T>. The caller can decide whether it
217 //   wishes to transfer ownership (by calling std::move(t) when passing t) or
218 //   retain its ref (by simply passing t directly).
219 //   In other words, use scoped_refptr like you would a std::unique_ptr except
220 //   in the odd case where it's required to hold on to a ref while handing one
221 //   to another component (if a component merely needs to use t on the stack
222 //   without keeping a ref: pass t as a raw T*).
223 template <class T>
224 class TRIVIAL_ABI scoped_refptr {
225  public:
226   typedef T element_type;
227 
228   constexpr scoped_refptr() = default;
229 
230   // Allow implicit construction from nullptr.
231   constexpr scoped_refptr(std::nullptr_t) {}
232 
233   // Constructs from a raw pointer. Note that this constructor allows implicit
234   // conversion from T* to scoped_refptr<T> which is strongly discouraged. If
235   // you are creating a new ref-counted object please use
236   // base::MakeRefCounted<T>() or base::WrapRefCounted<T>(). Otherwise you
237   // should move or copy construct from an existing scoped_refptr<T> to the
238   // ref-counted object.
239   scoped_refptr(T* p) : ptr_(p) {
240     if (ptr_)
241       AddRef(ptr_);
242   }
243 
244   // Copy constructor. This is required in addition to the copy conversion
245   // constructor below.
246   scoped_refptr(const scoped_refptr& r) : scoped_refptr(r.ptr_) {}
247 
248   // Copy conversion constructor.
249   template <typename U,
250             typename = std::enable_if_t<std::is_convertible_v<U*, T*>>>
251   scoped_refptr(const scoped_refptr<U>& r) : scoped_refptr(r.ptr_) {}
252 
253   // Move constructor. This is required in addition to the move conversion
254   // constructor below.
255   scoped_refptr(scoped_refptr&& r) noexcept : ptr_(r.ptr_) { r.ptr_ = nullptr; }
256 
257   // Move conversion constructor.
258   template <typename U,
259             typename = std::enable_if_t<std::is_convertible_v<U*, T*>>>
260   scoped_refptr(scoped_refptr<U>&& r) noexcept : ptr_(r.ptr_) {
261     r.ptr_ = nullptr;
262   }
263 
264   ~scoped_refptr() {
265     static_assert(!base::subtle::IsRefCountPreferenceOverridden(
266                       static_cast<T*>(nullptr), static_cast<T*>(nullptr)),
267                   "It's unsafe to override the ref count preference."
268                   " Please remove REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE"
269                   " from subclasses.");
270     if (ptr_)
271       Release(ptr_);
272   }
273 
274   T* get() const { return ptr_; }
275 
276   T& operator*() const {
277     DCHECK(ptr_);
278     return *ptr_;
279   }
280 
281   T* operator->() const {
282     DCHECK(ptr_);
283     return ptr_;
284   }
285 
286   scoped_refptr& operator=(std::nullptr_t) {
287     reset();
288     return *this;
289   }
290 
291   scoped_refptr& operator=(T* p) { return *this = scoped_refptr(p); }
292 
293   // Unified assignment operator.
294   scoped_refptr& operator=(scoped_refptr r) noexcept {
295     swap(r);
296     return *this;
297   }
298 
299   // Sets managed object to null and releases reference to the previous managed
300   // object, if it existed.
301   void reset() { scoped_refptr().swap(*this); }
302 
303   // Returns the owned pointer (if any), releasing ownership to the caller. The
304   // caller is responsible for managing the lifetime of the reference.
305   [[nodiscard]] T* release();
306 
307   void swap(scoped_refptr& r) noexcept { std::swap(ptr_, r.ptr_); }
308 
309   explicit operator bool() const { return ptr_ != nullptr; }
310 
311   template <typename U>
312   bool operator==(const scoped_refptr<U>& rhs) const {
313     return ptr_ == rhs.get();
314   }
315 
316   template <typename U>
317   bool operator!=(const scoped_refptr<U>& rhs) const {
318     return !operator==(rhs);
319   }
320 
321   template <typename U>
322   bool operator<(const scoped_refptr<U>& rhs) const {
323     return ptr_ < rhs.get();
324   }
325 
326  protected:
327   // This field is not a raw_ptr<> because it was filtered by the rewriter for:
328   // #union, #addr-of, #global-scope
329   RAW_PTR_EXCLUSION T* ptr_ = nullptr;
330 
331  private:
332   template <typename U>
333   friend scoped_refptr<U> base::AdoptRef(U*);
334   friend class ::base::SequencedTaskRunner;
335 
336   scoped_refptr(T* p, base::subtle::AdoptRefTag) : ptr_(p) {}
337 
338   // Friend required for move constructors that set r.ptr_ to null.
339   template <typename U>
340   friend class scoped_refptr;
341 
342   // Non-inline helpers to allow:
343   //     class Opaque;
344   //     extern template class scoped_refptr<Opaque>;
345   // Otherwise the compiler will complain that Opaque is an incomplete type.
346   static void AddRef(T* ptr);
347   static void Release(T* ptr);
348 };
349 
350 template <typename T>
351 T* scoped_refptr<T>::release() {
352   T* ptr = ptr_;
353   ptr_ = nullptr;
354   return ptr;
355 }
356 
357 // static
358 template <typename T>
359 void scoped_refptr<T>::AddRef(T* ptr) {
360   base::subtle::AssertRefCountBaseMatches(ptr, ptr);
361   ptr->AddRef();
362 }
363 
364 // static
365 template <typename T>
366 void scoped_refptr<T>::Release(T* ptr) {
367   base::subtle::AssertRefCountBaseMatches(ptr, ptr);
368   ptr->Release();
369 }
370 
371 template <typename T, typename U>
372 bool operator==(const scoped_refptr<T>& lhs, const U* rhs) {
373   return lhs.get() == rhs;
374 }
375 
376 template <typename T, typename U>
377 bool operator==(const T* lhs, const scoped_refptr<U>& rhs) {
378   return lhs == rhs.get();
379 }
380 
381 template <typename T>
382 bool operator==(const scoped_refptr<T>& lhs, std::nullptr_t null) {
383   return !static_cast<bool>(lhs);
384 }
385 
386 template <typename T>
387 bool operator==(std::nullptr_t null, const scoped_refptr<T>& rhs) {
388   return !static_cast<bool>(rhs);
389 }
390 
391 template <typename T, typename U>
392 bool operator!=(const scoped_refptr<T>& lhs, const U* rhs) {
393   return !operator==(lhs, rhs);
394 }
395 
396 template <typename T, typename U>
397 bool operator!=(const T* lhs, const scoped_refptr<U>& rhs) {
398   return !operator==(lhs, rhs);
399 }
400 
401 template <typename T>
402 bool operator!=(const scoped_refptr<T>& lhs, std::nullptr_t null) {
403   return !operator==(lhs, null);
404 }
405 
406 template <typename T>
407 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) {
408   return !operator==(null, rhs);
409 }
410 
411 template <typename T>
412 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) {
413   return out << p.get();
414 }
415 
416 template <typename T>
417 void swap(scoped_refptr<T>& lhs, scoped_refptr<T>& rhs) noexcept {
418   lhs.swap(rhs);
419 }
420 
421 #endif  // BASE_MEMORY_SCOPED_REFPTR_H_
422