Chromium Code Reviews| Index: skia/ext/refptr.h |
| diff --git a/skia/ext/refptr.h b/skia/ext/refptr.h |
| index a3900f61ba4502c0d59c3b8664cf6bb4dd3c4aa1..7a9ed5a0b0840514fe2e14d4761c0a1d1db864a3 100644 |
| --- a/skia/ext/refptr.h |
| +++ b/skia/ext/refptr.h |
| @@ -5,6 +5,7 @@ |
| #ifndef SKIA_EXT_REFPTR_H_ |
| #define SKIA_EXT_REFPTR_H_ |
| +#include "base/basictypes.h" |
| #include "third_party/skia/include/core/SkRefCnt.h" |
| namespace skia { |
| @@ -44,58 +45,155 @@ namespace skia { |
| template<typename T> |
| class RefPtr { |
| public: |
| - RefPtr() : ptr_(NULL) {} |
| + RefPtr() : ptr_(NULL) { |
| +#ifndef NDEBUG |
| + inside_receive_and_adopt_ref_ = false; |
| +#endif |
| + } |
| RefPtr(const RefPtr& other) |
| : ptr_(other.get()) { |
| SkSafeRef(ptr_); |
| +#ifndef NDEBUG |
| + inside_receive_and_adopt_ref_ = false; |
| +#endif |
| } |
| template<typename U> |
| RefPtr(const RefPtr<U>& other) |
| : ptr_(other.get()) { |
| SkSafeRef(ptr_); |
| +#ifndef NDEBUG |
| + inside_receive_and_adopt_ref_ = false; |
| +#endif |
| } |
| ~RefPtr() { |
| + ShouldNotBeInsideReceiveAndAdoptRef(); |
| clear(); |
| } |
| RefPtr& operator=(const RefPtr& other) { |
| + ShouldNotBeInsideReceiveAndAdoptRef(); |
| SkRefCnt_SafeAssign(ptr_, other.get()); |
| return *this; |
| } |
| template<typename U> |
| RefPtr& operator=(const RefPtr<U>& other) { |
| + ShouldNotBeInsideReceiveAndAdoptRef(); |
| SkRefCnt_SafeAssign(ptr_, other.get()); |
| return *this; |
| } |
| void clear() { |
| + ShouldNotBeInsideReceiveAndAdoptRef(); |
| T* to_unref = ptr_; |
| ptr_ = NULL; |
| SkSafeUnref(to_unref); |
| } |
| - T* get() const { return ptr_; } |
| - T& operator*() const { return *ptr_; } |
| - T* operator->() const { return ptr_; } |
| + T* get() const { |
| + ShouldNotBeInsideReceiveAndAdoptRef(); |
| + return ptr_; |
| + } |
| + T& operator*() const { |
| + ShouldNotBeInsideReceiveAndAdoptRef(); |
| + return *ptr_; |
| + } |
| + T* operator->() const { |
| + ShouldNotBeInsideReceiveAndAdoptRef(); |
| + return ptr_; |
| + } |
| typedef T* RefPtr::*unspecified_bool_type; |
| operator unspecified_bool_type() const { |
| + ShouldNotBeInsideReceiveAndAdoptRef(); |
| return ptr_ ? &RefPtr::ptr_ : NULL; |
| } |
| + class Receiver { |
| + public: |
| + ~Receiver() { |
| + refptr_->ShouldBeEmpty(); |
| + refptr_->ptr_ = ptr_; |
| + refptr_->inside_receive_and_adopt_ref_ = false; |
| + } |
| + |
| + operator T**() { return &ptr_; } |
| + |
| + private: |
| + friend class RefPtr; |
| + |
| + explicit Receiver(RefPtr* refptr) : refptr_(refptr), ptr_(NULL) { |
| + refptr_->ShouldBeEmpty(); |
| + } |
| + |
| + RefPtr* refptr_; |
| + T* ptr_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(Receiver); |
| + }; |
| + |
| + // Call this and pass the returned temporary it to a function taking a T** |
| + // argument. The returned temporary will set the original RefPtr to an object |
| + // with an unowned reference. |
| + // NOTE: Do not use this function as part of a subexpression where the RefPtr |
| + // is also used somewhere else. Destructors of temporaries are only run at the |
| + // end of a full expression so the initialization will not be complete and |
| + // the RefPtr will remain empty. |
|
Stephen White
2013/07/18 15:50:30
Maybe I'm old-fashioned, but I'm wondering if this
danakj
2013/07/18 15:59:36
My own preference would be to never receive someth
awong
2013/07/18 16:00:42
Yes...I agree but there's precedent (bleck). See
|
| + // |
| + // Bad (refptr will be NULL when it is dereffed): |
| + // Foo(refptr.ReceiveAndAdoptRef()) && refptr->Bar(); |
| + // Good: |
| + // bool ok = Foo(refptr.ReceiveAndAdoptRef()); |
| + // ok && refptr->Bar(); |
| + Receiver ReceiveAndAdoptRef() { |
| +#ifndef NDEBUG |
| + inside_receive_and_adopt_ref_ = true; |
| +#endif |
| + return Receiver(this); |
| + } |
| + |
| private: |
| T* ptr_; |
| +#ifndef NDEBUG |
| + bool inside_receive_and_adopt_ref_; |
| +#endif |
| + |
| + inline int ShouldNotBeInsideReceiveAndAdoptRef() const { |
| +#ifndef NDEBUG |
| + if (inside_receive_and_adopt_ref_) { |
| + // Crash. Can't use DCHECK here because blink includes this file. |
| + volatile int* a = NULL; |
| + return *a; |
| + } |
| +#endif |
| + return 0; |
| + } |
| + |
| + inline int ShouldBeEmpty() const { |
| +#ifndef NDEBUG |
| + if (ptr_ != NULL) { |
| + // Crash. Can't use DCHECK here because blink includes this file. |
| + volatile int* a = NULL; |
| + return *a; |
| + } |
| +#endif |
| + return 0; |
| + } |
| + |
| // This function cannot be public because Skia starts its ref-counted |
| // objects at refcnt=1. This makes it impossible to differentiate |
| // between a newly created object (that doesn't need to be ref'd) or an |
| // already existing object with one owner (that does need to be ref'd so that |
| // this RefPtr can also manage its lifetime). |
| - explicit RefPtr(T* ptr) : ptr_(ptr) {} |
| + explicit RefPtr(T* ptr) : ptr_(ptr) { |
| +#ifndef NDEBUG |
| + inside_receive_and_adopt_ref_ = false; |
| +#endif |
| + } |
| template<typename U> |
| friend RefPtr<U> AdoptRef(U* ptr); |