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