Index: base/memory/ref_counted.h |
diff --git a/base/memory/ref_counted.h b/base/memory/ref_counted.h |
index 6a689388d9d2d93ea0f1624c2316bdbadf044907..acbe67583221c5dad76393d2abab835f94acb7f3 100644 |
--- a/base/memory/ref_counted.h |
+++ b/base/memory/ref_counted.h |
@@ -269,17 +269,29 @@ class scoped_refptr { |
public: |
typedef T element_type; |
+ // RefCounted<T> or RefCountedThreadSafe<T> depending on the type implemented |
+ // by T (or T itself for RefCountedThreadSafe<T, CustomTraits> and the rare |
+ // use case of classes providing their own AddRef/Release methods and being |
+ // stored in a scoped_refptr). |
+ using RefCountedType = typename std::conditional< |
+ std::is_convertible<T*, base::RefCounted<T>*>::value, |
+ base::RefCounted<T>, |
+ typename std::conditional< |
+ std::is_convertible<T*, base::RefCountedThreadSafe<T>*>::value, |
+ base::RefCountedThreadSafe<T>, |
+ T>::type>::type; |
+ |
scoped_refptr() = default; |
scoped_refptr(T* p) : ptr_(p) { |
- if (ptr_) |
- AddRef(ptr_); |
+ if (ref_) |
+ AddRef(ref_); |
} |
// Copy constructor. |
scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) { |
- if (ptr_) |
- AddRef(ptr_); |
+ if (ref_) |
+ AddRef(ref_); |
} |
// Copy conversion constructor. |
@@ -287,8 +299,8 @@ class scoped_refptr { |
typename = typename std::enable_if< |
std::is_convertible<U*, T*>::value>::type> |
scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) { |
- if (ptr_) |
- AddRef(ptr_); |
+ if (ref_) |
+ AddRef(ref_); |
} |
// Move constructor. This is required in addition to the conversion |
@@ -304,8 +316,8 @@ class scoped_refptr { |
} |
~scoped_refptr() { |
- if (ptr_) |
- Release(ptr_); |
+ if (ref_) |
+ Release(ref_); |
} |
T* get() const { return ptr_; } |
@@ -322,12 +334,14 @@ class scoped_refptr { |
scoped_refptr<T>& operator=(T* p) { |
// AddRef first so that self assignment should work |
+ // Note: This AddRef() can't use the |ref_| trick, so assigning from a naked |
+ // pointer requires the assignor to have the full definition of |T|. |
if (p) |
AddRef(p); |
- T* old_ptr = ptr_; |
+ const RefCountedType* old_ref = ref_; |
ptr_ = p; |
- if (old_ptr) |
- Release(old_ptr); |
+ if (old_ref) |
+ Release(old_ref); |
return *this; |
} |
@@ -379,8 +393,22 @@ class scoped_refptr { |
} |
protected: |
+ //FIXME need to update |ref_| when updating |ptr_|. |
T* ptr_ = nullptr; |
+ // |ref_| merely points to |ptr_| but the type checking is done when |
+ // scoped_refptr is constructed instead of when it's used, this allows |
+ // callsites that merely do: |
+ // void PassRefToFoo(Foo* foo, scoped_refptr<T> t) { |
+ // foo->TakeRef(std::move(t)); |
+ // } |
+ // to compile without the full definition of |T| as they can perform |
+ // AddRef/Release operations on it without having to know that it implements |
+ // RefCountedInterface. |
+ //FIXME: This still doesn't work because template instantiations still need to |
+ //know the full type to derive |RefCountedType|... |
+ const RefCountedType* ref_ = ptr_; |
+ |
private: |
// Friend required for move constructors that set r.ptr_ to null. |
template <typename U> |
@@ -390,18 +418,22 @@ class scoped_refptr { |
// 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); |
+ static void AddRef(const RefCountedType* ref_type); |
+ static void Release(const RefCountedType* ref_type); |
}; |
+// static |
template <typename T> |
-void scoped_refptr<T>::AddRef(T* ptr) { |
- ptr->AddRef(); |
+void scoped_refptr<T>::AddRef( |
+ const scoped_refptr<T>::RefCountedType* ref_type) { |
+ ref_type->AddRef(); |
} |
+// static |
template <typename T> |
-void scoped_refptr<T>::Release(T* ptr) { |
- ptr->Release(); |
+void scoped_refptr<T>::Release( |
+ const scoped_refptr<T>::RefCountedType* ref_type) { |
+ ref_type->Release(); |
} |
// Handy utility for creating a scoped_refptr<T> out of a T* explicitly without |