Index: base/memory/ref_counted.h |
diff --git a/base/memory/ref_counted.h b/base/memory/ref_counted.h |
index 37012de0a6bcd3a548db9c4f5c1fe19c26582fef..98003972f7026a8765f0fc20dc307142b3b0ab67 100644 |
--- a/base/memory/ref_counted.h |
+++ b/base/memory/ref_counted.h |
@@ -19,21 +19,29 @@ |
#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 }; |
+ |
class BASE_EXPORT RefCountedBase { |
public: |
bool HasOneRef() const { return ref_count_ == 1; } |
protected: |
- RefCountedBase() |
- : ref_count_(0) |
+ explicit RefCountedBase(size_t initial_ref_count = 0) |
dcheng
2017/03/30 04:26:15
I think I would prefer that we have a default ctor
|
+ : ref_count_(initial_ref_count) { |
#if DCHECK_IS_ON() |
- , in_dtor_(false) |
+ DCHECK(initial_ref_count == 0 || initial_ref_count == 1); |
+ needs_adopt_ref_ = ref_count_ == 1; |
#endif |
- { |
} |
~RefCountedBase() { |
@@ -42,7 +50,6 @@ class BASE_EXPORT RefCountedBase { |
#endif |
} |
- |
void AddRef() const { |
// TODO(maruel): Add back once it doesn't assert 500 times/sec. |
// Current thread books the critical section "AddRelease" |
@@ -50,32 +57,49 @@ 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_; |
} |
// Returns true if the object should self-delete. |
bool Release() const { |
+ --ref_count_; |
+ |
// TODO(maruel): Add back once it doesn't assert 500 times/sec. |
// Current thread books the critical section "AddRelease" |
// without release it. |
// DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_); |
+ |
#if DCHECK_IS_ON() |
DCHECK(!in_dtor_); |
-#endif |
- if (--ref_count_ == 0) { |
-#if DCHECK_IS_ON() |
+ if (ref_count_ == 0) |
in_dtor_ = true; |
#endif |
- return true; |
- } |
- return false; |
+ |
+ return ref_count_ == 0; |
dcheng
2017/03/30 04:26:15
What is the purpose / necessity for these changes?
tzik
2017/03/30 13:16:27
Oops, this is a contamination from another CL: htt
|
} |
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_; |
+ |
#if DCHECK_IS_ON() |
- mutable bool in_dtor_; |
+ mutable bool needs_adopt_ref_; |
+ mutable bool in_dtor_ = false; |
#endif |
DFAKE_MUTEX(add_release_); |
@@ -88,7 +112,13 @@ class BASE_EXPORT RefCountedThreadSafeBase { |
bool HasOneRef() const; |
protected: |
- RefCountedThreadSafeBase(); |
+ explicit RefCountedThreadSafeBase(AtomicRefCount initial_ref_count = 0) |
+ : ref_count_(initial_ref_count) { |
+#if DCHECK_IS_ON() |
+ needs_adopt_ref_ = initial_ref_count == 1; |
+#endif |
+ } |
+ |
~RefCountedThreadSafeBase(); |
void AddRef() const; |
@@ -97,8 +127,19 @@ class BASE_EXPORT RefCountedThreadSafeBase { |
bool Release() const; |
private: |
- mutable AtomicRefCount ref_count_ = 0; |
+ 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_; |
+#if DCHECK_IS_ON() |
+ mutable bool needs_adopt_ref_; |
mutable bool in_dtor_ = false; |
#endif |
@@ -124,7 +165,8 @@ class BASE_EXPORT RefCountedThreadSafeBase { |
template <class T> |
class RefCounted : public subtle::RefCountedBase { |
public: |
- RefCounted() = default; |
+ explicit RefCounted(size_t initial_ref_count = 0) |
+ : subtle::RefCountedBase(initial_ref_count) {} |
void AddRef() const { |
subtle::RefCountedBase::AddRef(); |
@@ -174,7 +216,8 @@ struct DefaultRefCountedThreadSafeTraits { |
template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> > |
class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase { |
public: |
- RefCountedThreadSafe() = default; |
+ explicit RefCountedThreadSafe(AtomicRefCount initial_ref_count = 0) |
+ : subtle::RefCountedThreadSafeBase(initial_ref_count) {} |
void AddRef() const { |
subtle::RefCountedThreadSafeBase::AddRef(); |
@@ -214,6 +257,27 @@ 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* t) { |
+ DCHECK(!t || t->HasOneRef()); |
dcheng
2017/03/30 04:26:16
Hmm... why would we want to handle a null |t| here
tzik
2017/03/30 13:16:27
OK, updated to force nun-null.
|
+ if (t) |
+ t->Adopted(); |
+ return scoped_refptr<T>(t, subtle::kAdoptRefTag); |
+} |
+ |
+// 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)...); |
+ if (obj->HasOneRef()) |
+ return AdoptRef(obj); |
+ return scoped_refptr<T>(obj); |
dcheng
2017/03/30 04:26:16
Not sure if it's possible, but it would be nice if
tzik
2017/03/30 13:16:27
Trying that.
|
+} |
+ |
} // namespace base |
// |
@@ -381,6 +445,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; |