OLD | NEW |
---|---|
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef SKIA_EXT_REFPTR_H_ | 5 #ifndef SKIA_EXT_REFPTR_H_ |
6 #define SKIA_EXT_REFPTR_H_ | 6 #define SKIA_EXT_REFPTR_H_ |
7 | 7 |
8 #include "base/basictypes.h" | |
8 #include "third_party/skia/include/core/SkRefCnt.h" | 9 #include "third_party/skia/include/core/SkRefCnt.h" |
9 | 10 |
10 namespace skia { | 11 namespace skia { |
11 | 12 |
12 // When creating/receiving a ref-counted pointer from Skia, wrap that pointer in | 13 // When creating/receiving a ref-counted pointer from Skia, wrap that pointer in |
13 // this class to avoid dealing with the ref-counting and prevent leaks/crashes | 14 // this class to avoid dealing with the ref-counting and prevent leaks/crashes |
14 // due to ref-counting bugs. | 15 // due to ref-counting bugs. |
15 // | 16 // |
16 // Example of creating a new SkShader* and setting it on a SkPaint: | 17 // Example of creating a new SkShader* and setting it on a SkPaint: |
17 // skia::RefPtr<SkShader> shader = skia::AdoptRef(SkGradientShader::Create()); | 18 // skia::RefPtr<SkShader> shader = skia::AdoptRef(SkGradientShader::Create()); |
(...skipping 19 matching lines...) Expand all Loading... | |
37 // | 38 // |
38 // skia::RefPtr<SkShader> shader = skia::SharePtr(paint.getShader()); | 39 // skia::RefPtr<SkShader> shader = skia::SharePtr(paint.getShader()); |
39 // | 40 // |
40 // Never call ref() or unref() on the underlying ref-counted pointer. If you | 41 // Never call ref() or unref() on the underlying ref-counted pointer. If you |
41 // AdoptRef() the raw pointer immediately into a skia::RefPtr and always work | 42 // AdoptRef() the raw pointer immediately into a skia::RefPtr and always work |
42 // with skia::RefPtr instances instead, the ref-counting will be taken care of | 43 // with skia::RefPtr instances instead, the ref-counting will be taken care of |
43 // for you. | 44 // for you. |
44 template<typename T> | 45 template<typename T> |
45 class RefPtr { | 46 class RefPtr { |
46 public: | 47 public: |
47 RefPtr() : ptr_(NULL) {} | 48 RefPtr() : ptr_(NULL) { |
49 #ifndef NDEBUG | |
50 inside_receive_and_adopt_ref_ = false; | |
51 #endif | |
52 } | |
48 | 53 |
49 RefPtr(const RefPtr& other) | 54 RefPtr(const RefPtr& other) |
50 : ptr_(other.get()) { | 55 : ptr_(other.get()) { |
51 SkSafeRef(ptr_); | 56 SkSafeRef(ptr_); |
57 #ifndef NDEBUG | |
58 inside_receive_and_adopt_ref_ = false; | |
59 #endif | |
52 } | 60 } |
53 | 61 |
54 template<typename U> | 62 template<typename U> |
55 RefPtr(const RefPtr<U>& other) | 63 RefPtr(const RefPtr<U>& other) |
56 : ptr_(other.get()) { | 64 : ptr_(other.get()) { |
57 SkSafeRef(ptr_); | 65 SkSafeRef(ptr_); |
66 #ifndef NDEBUG | |
67 inside_receive_and_adopt_ref_ = false; | |
68 #endif | |
58 } | 69 } |
59 | 70 |
60 ~RefPtr() { | 71 ~RefPtr() { |
72 ShouldNotBeInsideReceiveAndAdoptRef(); | |
61 clear(); | 73 clear(); |
62 } | 74 } |
63 | 75 |
64 RefPtr& operator=(const RefPtr& other) { | 76 RefPtr& operator=(const RefPtr& other) { |
77 ShouldNotBeInsideReceiveAndAdoptRef(); | |
65 SkRefCnt_SafeAssign(ptr_, other.get()); | 78 SkRefCnt_SafeAssign(ptr_, other.get()); |
66 return *this; | 79 return *this; |
67 } | 80 } |
68 | 81 |
69 template<typename U> | 82 template<typename U> |
70 RefPtr& operator=(const RefPtr<U>& other) { | 83 RefPtr& operator=(const RefPtr<U>& other) { |
84 ShouldNotBeInsideReceiveAndAdoptRef(); | |
71 SkRefCnt_SafeAssign(ptr_, other.get()); | 85 SkRefCnt_SafeAssign(ptr_, other.get()); |
72 return *this; | 86 return *this; |
73 } | 87 } |
74 | 88 |
75 void clear() { | 89 void clear() { |
90 ShouldNotBeInsideReceiveAndAdoptRef(); | |
76 T* to_unref = ptr_; | 91 T* to_unref = ptr_; |
77 ptr_ = NULL; | 92 ptr_ = NULL; |
78 SkSafeUnref(to_unref); | 93 SkSafeUnref(to_unref); |
79 } | 94 } |
80 | 95 |
81 T* get() const { return ptr_; } | 96 T* get() const { |
82 T& operator*() const { return *ptr_; } | 97 ShouldNotBeInsideReceiveAndAdoptRef(); |
83 T* operator->() const { return ptr_; } | 98 return ptr_; |
99 } | |
100 T& operator*() const { | |
101 ShouldNotBeInsideReceiveAndAdoptRef(); | |
102 return *ptr_; | |
103 } | |
104 T* operator->() const { | |
105 ShouldNotBeInsideReceiveAndAdoptRef(); | |
106 return ptr_; | |
107 } | |
84 | 108 |
85 typedef T* RefPtr::*unspecified_bool_type; | 109 typedef T* RefPtr::*unspecified_bool_type; |
86 operator unspecified_bool_type() const { | 110 operator unspecified_bool_type() const { |
111 ShouldNotBeInsideReceiveAndAdoptRef(); | |
87 return ptr_ ? &RefPtr::ptr_ : NULL; | 112 return ptr_ ? &RefPtr::ptr_ : NULL; |
88 } | 113 } |
89 | 114 |
115 class Receiver { | |
116 public: | |
117 ~Receiver() { | |
118 refptr_->ShouldBeEmpty(); | |
119 refptr_->ptr_ = ptr_; | |
120 refptr_->inside_receive_and_adopt_ref_ = false; | |
121 } | |
122 | |
123 operator T**() { return &ptr_; } | |
124 | |
125 private: | |
126 friend class RefPtr; | |
127 | |
128 explicit Receiver(RefPtr* refptr) : refptr_(refptr), ptr_(NULL) { | |
129 refptr_->ShouldBeEmpty(); | |
130 } | |
131 | |
132 RefPtr* refptr_; | |
133 T* ptr_; | |
134 | |
135 DISALLOW_COPY_AND_ASSIGN(Receiver); | |
136 }; | |
137 | |
138 // Call this and pass the returned temporary it to a function taking a T** | |
139 // argument. The returned temporary will set the original RefPtr to an object | |
140 // with an unowned reference. | |
141 // NOTE: Do not use this function as part of a subexpression where the RefPtr | |
142 // is also used somewhere else. Destructors of temporaries are only run at the | |
143 // end of a full expression so the initialization will not be complete and | |
144 // 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
| |
145 // | |
146 // Bad (refptr will be NULL when it is dereffed): | |
147 // Foo(refptr.ReceiveAndAdoptRef()) && refptr->Bar(); | |
148 // Good: | |
149 // bool ok = Foo(refptr.ReceiveAndAdoptRef()); | |
150 // ok && refptr->Bar(); | |
151 Receiver ReceiveAndAdoptRef() { | |
152 #ifndef NDEBUG | |
153 inside_receive_and_adopt_ref_ = true; | |
154 #endif | |
155 return Receiver(this); | |
156 } | |
157 | |
90 private: | 158 private: |
91 T* ptr_; | 159 T* ptr_; |
92 | 160 |
161 #ifndef NDEBUG | |
162 bool inside_receive_and_adopt_ref_; | |
163 #endif | |
164 | |
165 inline int ShouldNotBeInsideReceiveAndAdoptRef() const { | |
166 #ifndef NDEBUG | |
167 if (inside_receive_and_adopt_ref_) { | |
168 // Crash. Can't use DCHECK here because blink includes this file. | |
169 volatile int* a = NULL; | |
170 return *a; | |
171 } | |
172 #endif | |
173 return 0; | |
174 } | |
175 | |
176 inline int ShouldBeEmpty() const { | |
177 #ifndef NDEBUG | |
178 if (ptr_ != NULL) { | |
179 // Crash. Can't use DCHECK here because blink includes this file. | |
180 volatile int* a = NULL; | |
181 return *a; | |
182 } | |
183 #endif | |
184 return 0; | |
185 } | |
186 | |
93 // This function cannot be public because Skia starts its ref-counted | 187 // This function cannot be public because Skia starts its ref-counted |
94 // objects at refcnt=1. This makes it impossible to differentiate | 188 // objects at refcnt=1. This makes it impossible to differentiate |
95 // between a newly created object (that doesn't need to be ref'd) or an | 189 // between a newly created object (that doesn't need to be ref'd) or an |
96 // already existing object with one owner (that does need to be ref'd so that | 190 // already existing object with one owner (that does need to be ref'd so that |
97 // this RefPtr can also manage its lifetime). | 191 // this RefPtr can also manage its lifetime). |
98 explicit RefPtr(T* ptr) : ptr_(ptr) {} | 192 explicit RefPtr(T* ptr) : ptr_(ptr) { |
193 #ifndef NDEBUG | |
194 inside_receive_and_adopt_ref_ = false; | |
195 #endif | |
196 } | |
99 | 197 |
100 template<typename U> | 198 template<typename U> |
101 friend RefPtr<U> AdoptRef(U* ptr); | 199 friend RefPtr<U> AdoptRef(U* ptr); |
102 | 200 |
103 template<typename U> | 201 template<typename U> |
104 friend RefPtr<U> SharePtr(U* ptr); | 202 friend RefPtr<U> SharePtr(U* ptr); |
105 }; | 203 }; |
106 | 204 |
107 // For objects that have an unowned reference (such as newly created objects). | 205 // For objects that have an unowned reference (such as newly created objects). |
108 template<typename T> | 206 template<typename T> |
109 RefPtr<T> AdoptRef(T* ptr) { return RefPtr<T>(ptr); } | 207 RefPtr<T> AdoptRef(T* ptr) { return RefPtr<T>(ptr); } |
110 | 208 |
111 // For objects that are already owned. This doesn't take ownership of existing | 209 // For objects that are already owned. This doesn't take ownership of existing |
112 // references and adds a new one. | 210 // references and adds a new one. |
113 template<typename T> | 211 template<typename T> |
114 RefPtr<T> SharePtr(T* ptr) { return RefPtr<T>(SkSafeRef(ptr)); } | 212 RefPtr<T> SharePtr(T* ptr) { return RefPtr<T>(SkSafeRef(ptr)); } |
115 | 213 |
116 } // namespace skia | 214 } // namespace skia |
117 | 215 |
118 #endif // SKIA_EXT_REFPTR_H_ | 216 #endif // SKIA_EXT_REFPTR_H_ |
OLD | NEW |