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

Unified Diff: skia/ext/refptr.h

Issue 19267024: cc: Don't leak a ref to SkColorFilter. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: filterleak: better Created 7 years, 5 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
« no previous file with comments | « cc/output/gl_renderer.cc ('k') | skia/ext/refptr_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
« no previous file with comments | « cc/output/gl_renderer.cc ('k') | skia/ext/refptr_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698