Home | History | Annotate | Download | only in memory
      1 // Copyright 2017 The Chromium Authors. All rights reserved.
      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/compiler_specific.h"
     15 #include "base/logging.h"
     16 #include "base/macros.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 
     28 template <typename T>
     29 scoped_refptr<T> AdoptRef(T* t);
     30 
     31 namespace subtle {
     32 
     33 enum AdoptRefTag { kAdoptRefTag };
     34 enum StartRefCountFromZeroTag { kStartRefCountFromZeroTag };
     35 enum StartRefCountFromOneTag { kStartRefCountFromOneTag };
     36 
     37 template <typename T, typename U, typename V>
     38 constexpr bool IsRefCountPreferenceOverridden(const T*,
     39                                               const RefCounted<U, V>*) {
     40   return !std::is_same<std::decay_t<decltype(T::kRefCountPreference)>,
     41                        std::decay_t<decltype(U::kRefCountPreference)>>::value;
     42 }
     43 
     44 template <typename T, typename U, typename V>
     45 constexpr bool IsRefCountPreferenceOverridden(
     46     const T*,
     47     const RefCountedThreadSafe<U, V>*) {
     48   return !std::is_same<std::decay_t<decltype(T::kRefCountPreference)>,
     49                        std::decay_t<decltype(U::kRefCountPreference)>>::value;
     50 }
     51 
     52 constexpr bool IsRefCountPreferenceOverridden(...) {
     53   return false;
     54 }
     55 
     56 }  // namespace subtle
     57 
     58 // Creates a scoped_refptr from a raw pointer without incrementing the reference
     59 // count. Use this only for a newly created object whose reference count starts
     60 // from 1 instead of 0.
     61 template <typename T>
     62 scoped_refptr<T> AdoptRef(T* obj) {
     63   using Tag = std::decay_t<decltype(T::kRefCountPreference)>;
     64   static_assert(std::is_same<subtle::StartRefCountFromOneTag, Tag>::value,
     65                 "Use AdoptRef only for the reference count starts from one.");
     66 
     67   DCHECK(obj);
     68   DCHECK(obj->HasOneRef());
     69   obj->Adopted();
     70   return scoped_refptr<T>(obj, subtle::kAdoptRefTag);
     71 }
     72 
     73 namespace subtle {
     74 
     75 template <typename T>
     76 scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromZeroTag) {
     77   return scoped_refptr<T>(obj);
     78 }
     79 
     80 template <typename T>
     81 scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromOneTag) {
     82   return AdoptRef(obj);
     83 }
     84 
     85 }  // namespace subtle
     86 
     87 // Constructs an instance of T, which is a ref counted type, and wraps the
     88 // object into a scoped_refptr<T>.
     89 template <typename T, typename... Args>
     90 scoped_refptr<T> MakeRefCounted(Args&&... args) {
     91   T* obj = new T(std::forward<Args>(args)...);
     92   return subtle::AdoptRefIfNeeded(obj, T::kRefCountPreference);
     93 }
     94 
     95 // Takes an instance of T, which is a ref counted type, and wraps the object
     96 // into a scoped_refptr<T>.
     97 template <typename T>
     98 scoped_refptr<T> WrapRefCounted(T* t) {
     99   return scoped_refptr<T>(t);
    100 }
    101 
    102 }  // namespace base
    103 
    104 //
    105 // A smart pointer class for reference counted objects.  Use this class instead
    106 // of calling AddRef and Release manually on a reference counted object to
    107 // avoid common memory leaks caused by forgetting to Release an object
    108 // reference.  Sample usage:
    109 //
    110 //   class MyFoo : public RefCounted<MyFoo> {
    111 //    ...
    112 //    private:
    113 //     friend class RefCounted<MyFoo>;  // Allow destruction by RefCounted<>.
    114 //     ~MyFoo();                        // Destructor must be private/protected.
    115 //   };
    116 //
    117 //   void some_function() {
    118 //     scoped_refptr<MyFoo> foo = MakeRefCounted<MyFoo>();
    119 //     foo->Method(param);
    120 //     // |foo| is released when this function returns
    121 //   }
    122 //
    123 //   void some_other_function() {
    124 //     scoped_refptr<MyFoo> foo = MakeRefCounted<MyFoo>();
    125 //     ...
    126 //     foo.reset();  // explicitly releases |foo|
    127 //     ...
    128 //     if (foo)
    129 //       foo->Method(param);
    130 //   }
    131 //
    132 // The above examples show how scoped_refptr<T> acts like a pointer to T.
    133 // Given two scoped_refptr<T> classes, it is also possible to exchange
    134 // references between the two objects, like so:
    135 //
    136 //   {
    137 //     scoped_refptr<MyFoo> a = MakeRefCounted<MyFoo>();
    138 //     scoped_refptr<MyFoo> b;
    139 //
    140 //     b.swap(a);
    141 //     // now, |b| references the MyFoo object, and |a| references nullptr.
    142 //   }
    143 //
    144 // To make both |a| and |b| in the above example reference the same MyFoo
    145 // object, simply use the assignment operator:
    146 //
    147 //   {
    148 //     scoped_refptr<MyFoo> a = MakeRefCounted<MyFoo>();
    149 //     scoped_refptr<MyFoo> b;
    150 //
    151 //     b = a;
    152 //     // now, |a| and |b| each own a reference to the same MyFoo object.
    153 //   }
    154 //
    155 // Also see Chromium's ownership and calling conventions:
    156 // https://chromium.googlesource.com/chromium/src/+/lkgr/styleguide/c++/c++.md#object-ownership-and-calling-conventions
    157 // Specifically:
    158 //   If the function (at least sometimes) takes a ref on a refcounted object,
    159 //   declare the param as scoped_refptr<T>. The caller can decide whether it
    160 //   wishes to transfer ownership (by calling std::move(t) when passing t) or
    161 //   retain its ref (by simply passing t directly).
    162 //   In other words, use scoped_refptr like you would a std::unique_ptr except
    163 //   in the odd case where it's required to hold on to a ref while handing one
    164 //   to another component (if a component merely needs to use t on the stack
    165 //   without keeping a ref: pass t as a raw T*).
    166 template <class T>
    167 class scoped_refptr {
    168  public:
    169   typedef T element_type;
    170 
    171   constexpr scoped_refptr() = default;
    172 
    173   // Constructs from raw pointer. constexpr if |p| is null.
    174   constexpr scoped_refptr(T* p) : ptr_(p) {
    175     if (ptr_)
    176       AddRef(ptr_);
    177   }
    178 
    179   // Copy constructor. This is required in addition to the copy conversion
    180   // constructor below.
    181   scoped_refptr(const scoped_refptr& r) : scoped_refptr(r.ptr_) {}
    182 
    183   // Copy conversion constructor.
    184   template <typename U,
    185             typename = typename std::enable_if<
    186                 std::is_convertible<U*, T*>::value>::type>
    187   scoped_refptr(const scoped_refptr<U>& r) : scoped_refptr(r.ptr_) {}
    188 
    189   // Move constructor. This is required in addition to the move conversion
    190   // constructor below.
    191   scoped_refptr(scoped_refptr&& r) noexcept : ptr_(r.ptr_) { r.ptr_ = nullptr; }
    192 
    193   // Move conversion constructor.
    194   template <typename U,
    195             typename = typename std::enable_if<
    196                 std::is_convertible<U*, T*>::value>::type>
    197   scoped_refptr(scoped_refptr<U>&& r) noexcept : ptr_(r.ptr_) {
    198     r.ptr_ = nullptr;
    199   }
    200 
    201   ~scoped_refptr() {
    202     static_assert(!base::subtle::IsRefCountPreferenceOverridden(
    203                       static_cast<T*>(nullptr), static_cast<T*>(nullptr)),
    204                   "It's unsafe to override the ref count preference."
    205                   " Please remove REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE"
    206                   " from subclasses.");
    207     if (ptr_)
    208       Release(ptr_);
    209   }
    210 
    211   T* get() const { return ptr_; }
    212 
    213   T& operator*() const {
    214     DCHECK(ptr_);
    215     return *ptr_;
    216   }
    217 
    218   T* operator->() const {
    219     DCHECK(ptr_);
    220     return ptr_;
    221   }
    222 
    223   scoped_refptr& operator=(T* p) { return *this = scoped_refptr(p); }
    224 
    225   // Unified assignment operator.
    226   scoped_refptr& operator=(scoped_refptr r) noexcept {
    227     swap(r);
    228     return *this;
    229   }
    230 
    231   // Sets managed object to null and releases reference to the previous managed
    232   // object, if it existed.
    233   void reset() { scoped_refptr().swap(*this); }
    234 
    235   void swap(scoped_refptr& r) noexcept { std::swap(ptr_, r.ptr_); }
    236 
    237   explicit operator bool() const { return ptr_ != nullptr; }
    238 
    239   template <typename U>
    240   bool operator==(const scoped_refptr<U>& rhs) const {
    241     return ptr_ == rhs.get();
    242   }
    243 
    244   template <typename U>
    245   bool operator!=(const scoped_refptr<U>& rhs) const {
    246     return !operator==(rhs);
    247   }
    248 
    249   template <typename U>
    250   bool operator<(const scoped_refptr<U>& rhs) const {
    251     return ptr_ < rhs.get();
    252   }
    253 
    254  protected:
    255   T* ptr_ = nullptr;
    256 
    257  private:
    258   template <typename U>
    259   friend scoped_refptr<U> base::AdoptRef(U*);
    260 
    261   scoped_refptr(T* p, base::subtle::AdoptRefTag) : ptr_(p) {}
    262 
    263   // Friend required for move constructors that set r.ptr_ to null.
    264   template <typename U>
    265   friend class scoped_refptr;
    266 
    267   // Non-inline helpers to allow:
    268   //     class Opaque;
    269   //     extern template class scoped_refptr<Opaque>;
    270   // Otherwise the compiler will complain that Opaque is an incomplete type.
    271   static void AddRef(T* ptr);
    272   static void Release(T* ptr);
    273 };
    274 
    275 // static
    276 template <typename T>
    277 void scoped_refptr<T>::AddRef(T* ptr) {
    278   ptr->AddRef();
    279 }
    280 
    281 // static
    282 template <typename T>
    283 void scoped_refptr<T>::Release(T* ptr) {
    284   ptr->Release();
    285 }
    286 
    287 template <typename T, typename U>
    288 bool operator==(const scoped_refptr<T>& lhs, const U* rhs) {
    289   return lhs.get() == rhs;
    290 }
    291 
    292 template <typename T, typename U>
    293 bool operator==(const T* lhs, const scoped_refptr<U>& rhs) {
    294   return lhs == rhs.get();
    295 }
    296 
    297 template <typename T>
    298 bool operator==(const scoped_refptr<T>& lhs, std::nullptr_t null) {
    299   return !static_cast<bool>(lhs);
    300 }
    301 
    302 template <typename T>
    303 bool operator==(std::nullptr_t null, const scoped_refptr<T>& rhs) {
    304   return !static_cast<bool>(rhs);
    305 }
    306 
    307 template <typename T, typename U>
    308 bool operator!=(const scoped_refptr<T>& lhs, const U* rhs) {
    309   return !operator==(lhs, rhs);
    310 }
    311 
    312 template <typename T, typename U>
    313 bool operator!=(const T* lhs, const scoped_refptr<U>& rhs) {
    314   return !operator==(lhs, rhs);
    315 }
    316 
    317 template <typename T>
    318 bool operator!=(const scoped_refptr<T>& lhs, std::nullptr_t null) {
    319   return !operator==(lhs, null);
    320 }
    321 
    322 template <typename T>
    323 bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) {
    324   return !operator==(null, rhs);
    325 }
    326 
    327 template <typename T>
    328 std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) {
    329   return out << p.get();
    330 }
    331 
    332 template <typename T>
    333 void swap(scoped_refptr<T>& lhs, scoped_refptr<T>& rhs) noexcept {
    334   lhs.swap(rhs);
    335 }
    336 
    337 #endif  // BASE_MEMORY_SCOPED_REFPTR_H_
    338