123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375 |
- // Copyright 2017 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #ifndef BASE_MEMORY_SCOPED_REFPTR_H_
- #define BASE_MEMORY_SCOPED_REFPTR_H_
- #include <stddef.h>
- #include <iosfwd>
- #include <type_traits>
- #include <utility>
- #include "base/check.h"
- #include "base/compiler_specific.h"
- #include "base/macros.h"
- template <class T>
- class scoped_refptr;
- namespace base {
- template <class, typename>
- class RefCounted;
- template <class, typename>
- class RefCountedThreadSafe;
- class SequencedTaskRunner;
- class WrappedPromise;
- template <typename T>
- scoped_refptr<T> AdoptRef(T* t);
- namespace internal {
- class BasePromise;
- } // namespace internal
- namespace subtle {
- enum AdoptRefTag { kAdoptRefTag };
- enum StartRefCountFromZeroTag { kStartRefCountFromZeroTag };
- enum StartRefCountFromOneTag { kStartRefCountFromOneTag };
- template <typename T, typename U, typename V>
- constexpr bool IsRefCountPreferenceOverridden(const T*,
- const RefCounted<U, V>*) {
- return !std::is_same<std::decay_t<decltype(T::kRefCountPreference)>,
- std::decay_t<decltype(U::kRefCountPreference)>>::value;
- }
- template <typename T, typename U, typename V>
- constexpr bool IsRefCountPreferenceOverridden(
- const T*,
- const RefCountedThreadSafe<U, V>*) {
- return !std::is_same<std::decay_t<decltype(T::kRefCountPreference)>,
- std::decay_t<decltype(U::kRefCountPreference)>>::value;
- }
- constexpr bool IsRefCountPreferenceOverridden(...) {
- return false;
- }
- } // namespace subtle
- // Creates a scoped_refptr from a raw pointer without incrementing the reference
- // count. Use this only for a newly created object whose reference count starts
- // from 1 instead of 0.
- template <typename T>
- scoped_refptr<T> AdoptRef(T* obj) {
- using Tag = std::decay_t<decltype(T::kRefCountPreference)>;
- static_assert(std::is_same<subtle::StartRefCountFromOneTag, Tag>::value,
- "Use AdoptRef only if the reference count starts from one.");
- DCHECK(obj);
- DCHECK(obj->HasOneRef());
- obj->Adopted();
- return scoped_refptr<T>(obj, subtle::kAdoptRefTag);
- }
- namespace subtle {
- template <typename T>
- scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromZeroTag) {
- return scoped_refptr<T>(obj);
- }
- template <typename T>
- scoped_refptr<T> AdoptRefIfNeeded(T* obj, StartRefCountFromOneTag) {
- return AdoptRef(obj);
- }
- } // namespace subtle
- // Constructs an instance of T, which is a ref counted type, and wraps the
- // object into a scoped_refptr<T>.
- template <typename T, typename... Args>
- scoped_refptr<T> MakeRefCounted(Args&&... args) {
- T* obj = new T(std::forward<Args>(args)...);
- return subtle::AdoptRefIfNeeded(obj, T::kRefCountPreference);
- }
- // Takes an instance of T, which is a ref counted type, and wraps the object
- // into a scoped_refptr<T>.
- template <typename T>
- scoped_refptr<T> WrapRefCounted(T* t) {
- return scoped_refptr<T>(t);
- }
- } // namespace base
- //
- // A smart pointer class for reference counted objects. Use this class instead
- // of calling AddRef and Release manually on a reference counted object to
- // avoid common memory leaks caused by forgetting to Release an object
- // reference. Sample usage:
- //
- // class MyFoo : public RefCounted<MyFoo> {
- // ...
- // private:
- // friend class RefCounted<MyFoo>; // Allow destruction by RefCounted<>.
- // ~MyFoo(); // Destructor must be private/protected.
- // };
- //
- // void some_function() {
- // scoped_refptr<MyFoo> foo = MakeRefCounted<MyFoo>();
- // foo->Method(param);
- // // |foo| is released when this function returns
- // }
- //
- // void some_other_function() {
- // scoped_refptr<MyFoo> foo = MakeRefCounted<MyFoo>();
- // ...
- // foo.reset(); // explicitly releases |foo|
- // ...
- // if (foo)
- // foo->Method(param);
- // }
- //
- // The above examples show how scoped_refptr<T> acts like a pointer to T.
- // Given two scoped_refptr<T> classes, it is also possible to exchange
- // references between the two objects, like so:
- //
- // {
- // scoped_refptr<MyFoo> a = MakeRefCounted<MyFoo>();
- // scoped_refptr<MyFoo> b;
- //
- // b.swap(a);
- // // now, |b| references the MyFoo object, and |a| references nullptr.
- // }
- //
- // To make both |a| and |b| in the above example reference the same MyFoo
- // object, simply use the assignment operator:
- //
- // {
- // scoped_refptr<MyFoo> a = MakeRefCounted<MyFoo>();
- // scoped_refptr<MyFoo> b;
- //
- // b = a;
- // // now, |a| and |b| each own a reference to the same MyFoo object.
- // }
- //
- // Also see Chromium's ownership and calling conventions:
- // https://chromium.googlesource.com/chromium/src/+/lkgr/styleguide/c++/c++.md#object-ownership-and-calling-conventions
- // Specifically:
- // If the function (at least sometimes) takes a ref on a refcounted object,
- // declare the param as scoped_refptr<T>. The caller can decide whether it
- // wishes to transfer ownership (by calling std::move(t) when passing t) or
- // retain its ref (by simply passing t directly).
- // In other words, use scoped_refptr like you would a std::unique_ptr except
- // in the odd case where it's required to hold on to a ref while handing one
- // to another component (if a component merely needs to use t on the stack
- // without keeping a ref: pass t as a raw T*).
- template <class T>
- class scoped_refptr {
- public:
- typedef T element_type;
- constexpr scoped_refptr() = default;
- // Allow implicit construction from nullptr.
- constexpr scoped_refptr(std::nullptr_t) {}
- // Constructs from a raw pointer. Note that this constructor allows implicit
- // conversion from T* to scoped_refptr<T> which is strongly discouraged. If
- // you are creating a new ref-counted object please use
- // base::MakeRefCounted<T>() or base::WrapRefCounted<T>(). Otherwise you
- // should move or copy construct from an existing scoped_refptr<T> to the
- // ref-counted object.
- scoped_refptr(T* p) : ptr_(p) {
- if (ptr_)
- AddRef(ptr_);
- }
- // Copy constructor. This is required in addition to the copy conversion
- // constructor below.
- scoped_refptr(const scoped_refptr& r) : scoped_refptr(r.ptr_) {}
- // Copy conversion constructor.
- template <typename U,
- typename = typename std::enable_if<
- std::is_convertible<U*, T*>::value>::type>
- scoped_refptr(const scoped_refptr<U>& r) : scoped_refptr(r.ptr_) {}
- // Move constructor. This is required in addition to the move conversion
- // constructor below.
- scoped_refptr(scoped_refptr&& r) noexcept : ptr_(r.ptr_) { r.ptr_ = nullptr; }
- // Move conversion constructor.
- template <typename U,
- typename = typename std::enable_if<
- std::is_convertible<U*, T*>::value>::type>
- scoped_refptr(scoped_refptr<U>&& r) noexcept : ptr_(r.ptr_) {
- r.ptr_ = nullptr;
- }
- ~scoped_refptr() {
- static_assert(!base::subtle::IsRefCountPreferenceOverridden(
- static_cast<T*>(nullptr), static_cast<T*>(nullptr)),
- "It's unsafe to override the ref count preference."
- " Please remove REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE"
- " from subclasses.");
- if (ptr_)
- Release(ptr_);
- }
- T* get() const { return ptr_; }
- T& operator*() const {
- DCHECK(ptr_);
- return *ptr_;
- }
- T* operator->() const {
- DCHECK(ptr_);
- return ptr_;
- }
- scoped_refptr& operator=(std::nullptr_t) {
- reset();
- return *this;
- }
- scoped_refptr& operator=(T* p) { return *this = scoped_refptr(p); }
- // Unified assignment operator.
- scoped_refptr& operator=(scoped_refptr r) noexcept {
- swap(r);
- return *this;
- }
- // Sets managed object to null and releases reference to the previous managed
- // object, if it existed.
- void reset() { scoped_refptr().swap(*this); }
- // Returns the owned pointer (if any), releasing ownership to the caller. The
- // caller is responsible for managing the lifetime of the reference.
- T* release() WARN_UNUSED_RESULT;
- void swap(scoped_refptr& r) noexcept { std::swap(ptr_, r.ptr_); }
- explicit operator bool() const { return ptr_ != nullptr; }
- template <typename U>
- bool operator==(const scoped_refptr<U>& rhs) const {
- return ptr_ == rhs.get();
- }
- template <typename U>
- bool operator!=(const scoped_refptr<U>& rhs) const {
- return !operator==(rhs);
- }
- template <typename U>
- bool operator<(const scoped_refptr<U>& rhs) const {
- return ptr_ < rhs.get();
- }
- protected:
- T* ptr_ = nullptr;
- private:
- template <typename U>
- friend scoped_refptr<U> base::AdoptRef(U*);
- friend class ::base::SequencedTaskRunner;
- // Friend access so these classes can use the constructor below as part of a
- // binary size optimization.
- friend class ::base::internal::BasePromise;
- friend class ::base::WrappedPromise;
- scoped_refptr(T* p, base::subtle::AdoptRefTag) : ptr_(p) {}
- // Friend required for move constructors that set r.ptr_ to null.
- template <typename U>
- friend class scoped_refptr;
- // Non-inline helpers to allow:
- // class Opaque;
- // extern template class scoped_refptr<Opaque>;
- // Otherwise the compiler will complain that Opaque is an incomplete type.
- static void AddRef(T* ptr);
- static void Release(T* ptr);
- };
- template <typename T>
- T* scoped_refptr<T>::release() {
- T* ptr = ptr_;
- ptr_ = nullptr;
- return ptr;
- }
- // static
- template <typename T>
- void scoped_refptr<T>::AddRef(T* ptr) {
- ptr->AddRef();
- }
- // static
- template <typename T>
- void scoped_refptr<T>::Release(T* ptr) {
- ptr->Release();
- }
- template <typename T, typename U>
- bool operator==(const scoped_refptr<T>& lhs, const U* rhs) {
- return lhs.get() == rhs;
- }
- template <typename T, typename U>
- bool operator==(const T* lhs, const scoped_refptr<U>& rhs) {
- return lhs == rhs.get();
- }
- template <typename T>
- bool operator==(const scoped_refptr<T>& lhs, std::nullptr_t null) {
- return !static_cast<bool>(lhs);
- }
- template <typename T>
- bool operator==(std::nullptr_t null, const scoped_refptr<T>& rhs) {
- return !static_cast<bool>(rhs);
- }
- template <typename T, typename U>
- bool operator!=(const scoped_refptr<T>& lhs, const U* rhs) {
- return !operator==(lhs, rhs);
- }
- template <typename T, typename U>
- bool operator!=(const T* lhs, const scoped_refptr<U>& rhs) {
- return !operator==(lhs, rhs);
- }
- template <typename T>
- bool operator!=(const scoped_refptr<T>& lhs, std::nullptr_t null) {
- return !operator==(lhs, null);
- }
- template <typename T>
- bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) {
- return !operator==(null, rhs);
- }
- template <typename T>
- std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) {
- return out << p.get();
- }
- template <typename T>
- void swap(scoped_refptr<T>& lhs, scoped_refptr<T>& rhs) noexcept {
- lhs.swap(rhs);
- }
- #endif // BASE_MEMORY_SCOPED_REFPTR_H_
|