Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(367)

Unified Diff: base/memory/ref_counted.h

Issue 2723423002: Start BindStateBase ref count from 1 instead of 0 (Closed)
Patch Set: . Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: base/memory/ref_counted.h
diff --git a/base/memory/ref_counted.h b/base/memory/ref_counted.h
index 503a86a45f02bd5d65c7ad0a2c6912a923eba0d7..9c57978d88ee176597294b2495e352fd017c4c05 100644
--- a/base/memory/ref_counted.h
+++ b/base/memory/ref_counted.h
@@ -19,16 +19,31 @@
#include "base/threading/thread_collision_warner.h"
#include "build/build_config.h"
+template <class T>
+class scoped_refptr;
+
namespace base {
+template <typename T>
+scoped_refptr<T> AdoptRef(T* t);
+
namespace subtle {
+enum AdoptRefTag { kAdoptRefTag };
+enum StartRefCountFromZeroTag { kStartRefCountFromZeroTag };
+enum StartRefCountFromOneTag { kStartRefCountFromOneTag };
+
class BASE_EXPORT RefCountedBase {
public:
bool HasOneRef() const { return ref_count_ == 1; }
protected:
- RefCountedBase() {}
+ explicit RefCountedBase(StartRefCountFromZeroTag) {}
+ explicit RefCountedBase(StartRefCountFromOneTag) : ref_count_(1) {
+#if DCHECK_IS_ON()
+ needs_adopt_ref_ = true;
+#endif
+ }
~RefCountedBase() {
#if DCHECK_IS_ON()
@@ -43,6 +58,10 @@ class BASE_EXPORT RefCountedBase {
// DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
#if DCHECK_IS_ON()
DCHECK(!in_dtor_);
+ DCHECK(!needs_adopt_ref_)
+ << "This RefCounted object is created with non-zero reference count."
+ << " The first reference to such a object has to be made by AdoptRef or"
+ << " MakeShared.";
#endif
++ref_count_;
@@ -67,8 +86,20 @@ class BASE_EXPORT RefCountedBase {
}
private:
+ template <typename U>
+ friend scoped_refptr<U> base::AdoptRef(U*);
+
+ void Adopted() const {
+#if DCHECK_IS_ON()
+ DCHECK(needs_adopt_ref_);
+ needs_adopt_ref_ = false;
+#endif
+ }
+
mutable size_t ref_count_ = 0;
+
#if DCHECK_IS_ON()
+ mutable bool needs_adopt_ref_ = false;
mutable bool in_dtor_ = false;
#endif
@@ -82,7 +113,13 @@ class BASE_EXPORT RefCountedThreadSafeBase {
bool HasOneRef() const;
protected:
- RefCountedThreadSafeBase();
+ explicit RefCountedThreadSafeBase(StartRefCountFromZeroTag) {}
+ explicit RefCountedThreadSafeBase(StartRefCountFromOneTag) : ref_count_(1) {
+#if DCHECK_IS_ON()
+ needs_adopt_ref_ = true;
+#endif
+ }
+
~RefCountedThreadSafeBase();
void AddRef() const;
@@ -91,8 +128,19 @@ class BASE_EXPORT RefCountedThreadSafeBase {
bool Release() const;
private:
+ template <typename U>
+ friend scoped_refptr<U> base::AdoptRef(U*);
+
+ void Adopted() const {
+#if DCHECK_IS_ON()
+ DCHECK(needs_adopt_ref_);
+ needs_adopt_ref_ = false;
+#endif
+ }
+
mutable AtomicRefCount ref_count_ = 0;
#if DCHECK_IS_ON()
+ mutable bool needs_adopt_ref_ = false;
mutable bool in_dtor_ = false;
#endif
@@ -118,7 +166,10 @@ class BASE_EXPORT RefCountedThreadSafeBase {
template <class T>
class RefCounted : public subtle::RefCountedBase {
public:
- RefCounted() = default;
+ static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference =
+ subtle::kStartRefCountFromZeroTag;
+
+ RefCounted() : subtle::RefCountedBase(T::kRefCountPreference) {}
void AddRef() const {
subtle::RefCountedBase::AddRef();
@@ -134,7 +185,7 @@ class RefCounted : public subtle::RefCountedBase {
~RefCounted() = default;
private:
- DISALLOW_COPY_AND_ASSIGN(RefCounted<T>);
+ DISALLOW_COPY_AND_ASSIGN(RefCounted);
};
// Forward declaration.
@@ -168,7 +219,11 @@ struct DefaultRefCountedThreadSafeTraits {
template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> >
class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {
public:
- RefCountedThreadSafe() = default;
+ static constexpr subtle::StartRefCountFromZeroTag kRefCountPreference =
+ subtle::kStartRefCountFromZeroTag;
+
+ explicit RefCountedThreadSafe()
+ : subtle::RefCountedThreadSafeBase(T::kRefCountPreference) {}
void AddRef() const {
subtle::RefCountedThreadSafeBase::AddRef();
@@ -208,6 +263,44 @@ class RefCountedData
~RefCountedData() = default;
};
+// 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 = typename std::decay<decltype(T::kRefCountPreference)>::type;
+ static_assert(std::is_same<subtle::StartRefCountFromOneTag, Tag>::value,
+ "Use AdoptRef only for 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);
+ return scoped_refptr<T>(obj);
+}
+
+} // namespace subtle
+
+// Constructs an instance of T, which is a ref counted type, and wraps the
+// object into a scoped_refptr.
+template <typename T, typename... Args>
+scoped_refptr<T> MakeShared(Args&&... args) {
+ T* obj = new T(std::forward<Args>(args)...);
+ return subtle::AdoptRefIfNeeded(obj, T::kRefCountPreference);
+}
+
} // namespace base
//
@@ -375,6 +468,11 @@ class scoped_refptr {
T* ptr_ = nullptr;
private:
+ template <typename U>
+ friend scoped_refptr<U> base::AdoptRef(U*);
+
+ 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;

Powered by Google App Engine
This is Rietveld 408576698