Index: base/memory/ref_counted.h |
diff --git a/base/memory/ref_counted.h b/base/memory/ref_counted.h |
index 960c8a28453122a5e00a2cb72d5f420e7b642f15..c9ba42401ed43976aa3e0317d72906cc81e612ab 100644 |
--- a/base/memory/ref_counted.h |
+++ b/base/memory/ref_counted.h |
@@ -271,41 +271,46 @@ class scoped_refptr { |
scoped_refptr() {} |
- scoped_refptr(T* p) : ptr_(p) { |
+ scoped_refptr(T* p) : ptr_(p), ptr_caller_(&PtrCallerImpl) { |
if (ptr_) |
- AddRef(ptr_); |
+ ptr_caller_(ptr_, PtrCall::AddRef); |
} |
// Copy constructor. |
- scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) { |
+ scoped_refptr(const scoped_refptr<T>& r) |
+ : ptr_(r.ptr_), ptr_caller_(r.ptr_caller_) { |
if (ptr_) |
- AddRef(ptr_); |
+ ptr_caller_(ptr_, PtrCall::AddRef); |
} |
// 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) : ptr_(r.get()) { |
+ scoped_refptr(const scoped_refptr<U>& r) |
+ : ptr_(r.get()), ptr_caller_(&PtrCallerImpl) { |
if (ptr_) |
- AddRef(ptr_); |
+ ptr_caller_(ptr_, PtrCall::AddRef); |
} |
// Move constructor. This is required in addition to the conversion |
// constructor below in order for clang to warn about pessimizing moves. |
- scoped_refptr(scoped_refptr&& r) : ptr_(r.get()) { r.ptr_ = nullptr; } |
+ scoped_refptr(scoped_refptr&& r) : ptr_(r.get()), ptr_caller_(r.ptr_caller_) { |
+ 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) : ptr_(r.get()) { |
+ scoped_refptr(scoped_refptr<U>&& r) |
+ : ptr_(r.get()), ptr_caller_(&PtrCallerImpl) { |
r.ptr_ = nullptr; |
} |
~scoped_refptr() { |
if (ptr_) |
- Release(ptr_); |
+ ptr_caller_(ptr_, PtrCall::Release); |
} |
T* get() const { return ptr_; } |
@@ -321,23 +326,19 @@ class scoped_refptr { |
} |
scoped_refptr<T>& operator=(T* p) { |
- // AddRef first so that self assignment should work |
- if (p) |
- AddRef(p); |
- T* old_ptr = ptr_; |
- ptr_ = p; |
- if (old_ptr) |
- Release(old_ptr); |
+ Assign(p, &PtrCallerImpl); |
return *this; |
} |
scoped_refptr<T>& operator=(const scoped_refptr<T>& r) { |
- return *this = r.ptr_; |
+ Assign(r.ptr_, r.ptr_caller_); |
+ return *this; |
} |
template <typename U> |
scoped_refptr<T>& operator=(const scoped_refptr<U>& r) { |
- return *this = r.get(); |
+ Assign(r.get(), &PtrCallerImpl); |
+ return *this; |
} |
scoped_refptr<T>& operator=(scoped_refptr<T>&& r) { |
@@ -354,11 +355,13 @@ class scoped_refptr { |
void swap(T** pp) { |
T* p = ptr_; |
ptr_ = *pp; |
+ ptr_caller_ = &PtrCallerImpl; |
*pp = p; |
} |
void swap(scoped_refptr<T>& r) { |
- swap(&r.ptr_); |
+ std::swap(ptr_, r.ptr_); |
+ std::swap(ptr_caller_, r.ptr_caller_); |
} |
explicit operator bool() const { return ptr_ != nullptr; } |
@@ -379,33 +382,41 @@ class scoped_refptr { |
} |
protected: |
+ enum class PtrCall { AddRef, Release }; |
+ using PtrCallerFunction = void (*)(T* ptr, PtrCall call); |
+ |
+ static void PtrCallerImpl(T* ptr, PtrCall call) { |
+ switch (call) { |
+ case PtrCall::AddRef: |
+ ptr->AddRef(); |
+ break; |
+ case PtrCall::Release: |
+ ptr->Release(); |
+ break; |
+ } |
+ } |
+ |
T* ptr_ = nullptr; |
+ PtrCallerFunction ptr_caller_ = nullptr; |
private: |
- // 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); |
+ void Assign(T* p, PtrCallerFunction caller) { |
+ // AddRef first so that self assignment should work |
+ if (p) |
+ caller(p, PtrCall::AddRef); |
+ T* old_ptr = ptr_; |
+ PtrCallerFunction old_caller = ptr_caller_; |
+ ptr_ = p; |
+ ptr_caller_ = caller; |
+ if (old_ptr) |
+ old_caller(old_ptr, PtrCall::Release); |
+ // Release above can potentially delete this object |
+ } |
}; |
-// 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(); |
-} |
- |
// Handy utility for creating a scoped_refptr<T> out of a T* explicitly without |
// having to retype all the template arguments |
template <typename T> |