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

Side by Side Diff: base/memory/scoped_ptr.h

Issue 11149006: Extend scoped_ptr to be closer to unique_ptr. Support custom deleters, and deleting arrays. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: I think this works. Created 8 years, 2 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | base/memory/scoped_ptr_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 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 // Scopers help you manage ownership of a pointer, helping you easily manage the 5 // Scopers help you manage ownership of a pointer, helping you easily manage the
6 // a pointer within a scope, and automatically destroying the pointer at the 6 // a pointer within a scope, and automatically destroying the pointer at the
7 // end of a scope. There are two main classes you will use, which correspond 7 // end of a scope. There are two main classes you will use, which correspond
8 // to the operators new/delete and new[]/delete[]. 8 // to the operators new/delete and new[]/delete[].
9 // 9 //
10 // Example usage (scoped_ptr): 10 // Example usage (scoped_ptr):
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
87 #ifndef BASE_MEMORY_SCOPED_PTR_H_ 87 #ifndef BASE_MEMORY_SCOPED_PTR_H_
88 #define BASE_MEMORY_SCOPED_PTR_H_ 88 #define BASE_MEMORY_SCOPED_PTR_H_
89 89
90 // This is an implementation designed to match the anticipated future TR2 90 // This is an implementation designed to match the anticipated future TR2
91 // implementation of the scoped_ptr class, and its closely-related brethren, 91 // implementation of the scoped_ptr class, and its closely-related brethren,
92 // scoped_array, scoped_ptr_malloc. 92 // scoped_array, scoped_ptr_malloc.
93 93
94 #include <assert.h> 94 #include <assert.h>
95 #include <stddef.h> 95 #include <stddef.h>
96 #include <stdlib.h> 96 #include <stdlib.h>
97 #include <algorithm> // TODO(ajwong): Do we really want std::swap?
Jeffrey Yasskin 2012/10/13 01:33:29 Yeah, we need to include std::swap in the overload
awong 2012/10/18 02:46:15 Fixed locally. Will be up in next patch.
97 98
98 #include "base/basictypes.h" 99 #include "base/basictypes.h"
99 #include "base/compiler_specific.h" 100 #include "base/compiler_specific.h"
100 #include "base/move.h" 101 #include "base/move.h"
101 #include "base/template_util.h" 102 #include "base/template_util.h"
102 103
103 namespace base { 104 namespace base {
104 105
105 namespace subtle { 106 namespace subtle {
106 class RefCountedBase; 107 class RefCountedBase;
107 class RefCountedThreadSafeBase; 108 class RefCountedThreadSafeBase;
108 } // namespace subtle 109 } // namespace subtle
109 110
111 // Function object which deletes its parameter, which must be a pointer.
112 // If C is an array type, invokes 'delete[]' on the parameter; otherwise,
113 // invokes 'delete'. The default deleter for scoped_ptr<T>.
114 template <class C>
115 struct DefaultDeleter {
116 inline void operator()(C* ptr) const {
117 enum { type_must_be_complete = sizeof(C) };
118 delete ptr;
119 }
120 };
121
122 // Specialization of DefaultDeleter for array types.
123 template <class C>
124 struct DefaultDeleter<C[]> {
125 inline void operator()(C* ptr) const {
126 enum { type_must_be_complete = sizeof(C) };
127 delete[] ptr;
128 }
129 };
130
131 // Function object which invokes 'free' on its parameter, which must be
132 // a pointer. Can be used to store malloc-allocated pointers in scoped_ptr:
133 //
134 // scoped_ptr<int, base::FreeDeleter> foo_ptr(
135 // static_cast<int>(malloc(sizeof(int))));
136 struct FreeDeleter {
137 inline void operator()(void* ptr) const {
138 free(ptr);
139 }
140 };
141
110 namespace internal { 142 namespace internal {
111 143
112 template <typename T> struct IsNotRefCounted { 144 template <typename T> struct IsNotRefCounted {
113 enum { 145 enum {
114 value = !base::is_convertible<T*, base::subtle::RefCountedBase*>::value && 146 value = !base::is_convertible<T*, base::subtle::RefCountedBase*>::value &&
115 !base::is_convertible<T*, base::subtle::RefCountedThreadSafeBase*>:: 147 !base::is_convertible<T*, base::subtle::RefCountedThreadSafeBase*>::
116 value 148 value
117 }; 149 };
118 }; 150 };
119 151
152 // Minimal implementation of the core logic of scoped_ptr, suitable for
153 // reuse in both scoped_ptr and its specialization.
154 template <class C, class D>
Jeffrey Yasskin 2012/10/13 01:33:29 I'd try for better names than "C" and "D".
awong 2012/10/18 02:46:15 Done.
155 class scoped_ptr_impl {
156 public:
157 explicit scoped_ptr_impl(C* p) : data_(p) { }
158
159 ~scoped_ptr_impl() {
160 if (data_.ptr != NULL) {
161 (static_cast<D&>(data_))(data_.ptr);
Jeffrey Yasskin 2012/10/13 01:33:29 Give data_ a .deleter() method? Strictly, you coul
awong 2012/10/18 02:46:15 Done.
162 }
163 }
164
165 void reset(C* p) {
166 // This self-reset check is deprecated.
167 if (p != data_.ptr) {
168 if (data_.ptr != NULL) {
169 // Note that this can lead to undefined behavior and memory leaks
170 // in the unlikely but possible case that get_deleter()(get())
171 // indirectly deletes this. The fix is to reset ptr_ before deleting
172 // its old value, but first we need to clean up the code that relies
173 // on the current sequencing. See http://b/6987235.
Jeffrey Yasskin 2012/10/13 01:33:29 Clean up b/ references before committing.
awong 2012/10/18 02:46:15 Removed. Still need to file a bug, but first I wa
174 (static_cast<D&>(data_))(data_.ptr);
175 }
176 data_.ptr = p;
177 }
178 }
179
180 C* get() const { return data_.ptr; }
181
182 void swap(scoped_ptr_impl& p2) {
183 // Standard swap idiom: 'using std::swap' ensures that std::swap is
184 // present in the overload set, but we call swap unqualified so that
185 // any more-specific overloads can be used, if available.
186 using std::swap;
187 swap(static_cast<D&>(data_), static_cast<D&>(p2.data_));
188 swap(data_.ptr, p2.data_.ptr);
189 }
190
191 C* release() {
192 C* retVal = data_.ptr;
193 data_.ptr = NULL;
194 return retVal;
195 }
196
197 private:
198 // Use the empty base class optimization to allow us to have a D member,
199 // while avoiding any space overhead for it when D is an empty class.
200 // See e.g. http://www.cantrip.org/emptyopt.html for a good discussion of
201 // this technique.
202 struct Data : public D {
203 explicit Data(C* ptr_in) : ptr(ptr_in) {}
204
205 C* ptr;
206 };
207
208 Data data_;
209
210 // Disallow copy and assignment.
211 scoped_ptr_impl(const scoped_ptr_impl&);
212 scoped_ptr_impl& operator=(const scoped_ptr_impl&);
213 };
214
215
120 } // namespace internal 216 } // namespace internal
217
121 } // namespace base 218 } // namespace base
122 219
123 // A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T> 220 // A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>
124 // automatically deletes the pointer it holds (if any). 221 // automatically deletes the pointer it holds (if any).
125 // That is, scoped_ptr<T> owns the T object that it points to. 222 // That is, scoped_ptr<T> owns the T object that it points to.
126 // Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to a T object. 223 // Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to a T object.
127 // Also like T*, scoped_ptr<T> is thread-compatible, and once you 224 // Also like T*, scoped_ptr<T> is thread-compatible, and once you
128 // dereference it, you get the thread safety guarantees of T. 225 // dereference it, you get the thread safety guarantees of T.
129 // 226 //
130 // The size of a scoped_ptr is small: 227 // The size of a scoped_ptr is small:
131 // sizeof(scoped_ptr<C>) == sizeof(C*) 228 // sizeof(scoped_ptr<C>) == sizeof(C*)
132 template <class C> 229 template <class C, class D = base::DefaultDeleter<C> >
133 class scoped_ptr { 230 class scoped_ptr {
134 MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue) 231 MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
135 232
136 COMPILE_ASSERT(base::internal::IsNotRefCounted<C>::value, 233 COMPILE_ASSERT(base::internal::IsNotRefCounted<C>::value,
137 C_is_refcounted_type_and_needs_scoped_refptr); 234 C_is_refcounted_type_and_needs_scoped_refptr);
138 235
139 public: 236 public:
140 237
141 // The element type 238 // The element type
142 typedef C element_type; 239 typedef C element_type;
240 typedef D deleter_type;
143 241
144 // Constructor. Defaults to initializing with NULL. 242 // Constructor. Defaults to initializing with NULL.
145 // There is no way to create an uninitialized scoped_ptr. 243 // There is no way to create an uninitialized scoped_ptr.
146 // The input parameter must be allocated with new. 244 // The input parameter must be allocated with new.
147 explicit scoped_ptr(C* p = NULL) : ptr_(p) { } 245 explicit scoped_ptr(C* p = NULL) : impl_(p) { }
148 246
149 // Constructor. Allows construction from a scoped_ptr rvalue for a 247 // Constructor. Allows construction from a scoped_ptr rvalue for a
150 // convertible type. 248 // convertible type.
151 template <typename U> 249 //
152 scoped_ptr(scoped_ptr<U> other) : ptr_(other.release()) { } 250 // TODO(ajwong): Correctly handle conversion with different deleters which
251 // can happen on an upcast. What I think needs to happen is that we need to
252 // be able to converst V to D.
253 template <typename U, typename V>
254 scoped_ptr(scoped_ptr<U, V> other) : impl_(NULL) { //: impl_(other.release()) {
255 }
153 256
154 // Constructor. Move constructor for C++03 move emulation of this type. 257 // Constructor. Move constructor for C++03 move emulation of this type.
155 scoped_ptr(RValue rvalue) 258 scoped_ptr(RValue rvalue)
156 : ptr_(rvalue.object->release()) { 259 : impl_(rvalue.object->release()) {
157 }
158
159 // Destructor. If there is a C object, delete it.
160 // We don't need to test ptr_ == NULL because C++ does that for us.
161 ~scoped_ptr() {
162 enum { type_must_be_complete = sizeof(C) };
163 delete ptr_;
164 } 260 }
165 261
166 // operator=. Allows assignment from a scoped_ptr rvalue for a convertible 262 // operator=. Allows assignment from a scoped_ptr rvalue for a convertible
167 // type. 263 // type.
168 template <typename U> 264 template <typename U>
169 scoped_ptr& operator=(scoped_ptr<U> rhs) { 265 scoped_ptr& operator=(scoped_ptr<U> rhs) {
170 reset(rhs.release()); 266 reset(rhs.release());
171 return *this; 267 return *this;
172 } 268 }
173 269
174 // operator=. Move operator= for C++03 move emulation of this type. 270 // operator=. Move operator= for C++03 move emulation of this type.
175 scoped_ptr& operator=(RValue rhs) { 271 scoped_ptr& operator=(RValue rhs) {
176 swap(*rhs->object); 272 swap(*rhs->object);
177 return *this; 273 return *this;
178 } 274 }
179 275
180 // Reset. Deletes the current owned object, if any. 276 // Reset. Deletes the current owned object, if any.
181 // Then takes ownership of a new object, if given. 277 // Then takes ownership of a new object, if given.
182 // this->reset(this->get()) works. 278 // this->reset(this->get()) works, but this behavior is DEPRECATED, and
279 // will be removed
280 //
281 // TODO(ajwong): File bug of it.
183 void reset(C* p = NULL) { 282 void reset(C* p = NULL) {
283 impl_.reset(p);
284 /*
184 if (p != ptr_) { 285 if (p != ptr_) {
185 enum { type_must_be_complete = sizeof(C) }; 286 C* old_ptr = ptr_;
186 delete ptr_;
187 ptr_ = p; 287 ptr_ = p;
288 // TODO(ajwong): This changes the delete ordering. Verify it's okay.
289 if (old_ptr != NULL) {
290 D()(old_ptr);
291 }
188 } 292 }
293 */
189 } 294 }
190 295
191 // Accessors to get the owned object. 296 // Accessors to get the owned object.
192 // operator* and operator-> will assert() if there is no current object. 297 // operator* and operator-> will assert() if there is no current object.
193 C& operator*() const { 298 C& operator*() const {
194 assert(ptr_ != NULL); 299 assert(impl_.get() != NULL);
195 return *ptr_; 300 return *impl_.get();
196 } 301 }
197 C* operator->() const { 302 C* operator->() const {
198 assert(ptr_ != NULL); 303 assert(impl_.get() != NULL);
199 return ptr_; 304 return impl_.get();
200 } 305 }
201 C* get() const { return ptr_; } 306 C* get() const { return impl_.get(); }
202 307
203 // Allow scoped_ptr<C> to be used in boolean expressions, but not 308 // Allow scoped_ptr<C> to be used in boolean expressions, but not
204 // implicitly convertible to a real bool (which is dangerous). 309 // implicitly convertible to a real bool (which is dangerous).
205 typedef C* scoped_ptr::*Testable; 310 typedef C* scoped_ptr::*Testable;
206 operator Testable() const { return ptr_ ? &scoped_ptr::ptr_ : NULL; } 311 operator Testable() const { return impl_.get() ? &impl_.get() : NULL; }
207 312
208 // Comparison operators. 313 // Comparison operators.
209 // These return whether two scoped_ptr refer to the same object, not just to 314 // These return whether two scoped_ptr refer to the same object, not just to
210 // two different but equal objects. 315 // two different but equal objects.
211 bool operator==(C* p) const { return ptr_ == p; } 316 bool operator==(C* p) const { return impl_.get() == p; }
212 bool operator!=(C* p) const { return ptr_ != p; } 317 bool operator!=(C* p) const { return impl_.get() != p; }
213 318
214 // Swap two scoped pointers. 319 // Swap two scoped pointers.
215 void swap(scoped_ptr& p2) { 320 void swap(scoped_ptr& p2) {
216 C* tmp = ptr_; 321 impl_.swap(p2.impl_);
217 ptr_ = p2.ptr_;
218 p2.ptr_ = tmp;
219 } 322 }
220 323
221 // Release a pointer. 324 // Release a pointer.
222 // The return value is the current pointer held by this object. 325 // The return value is the current pointer held by this object.
223 // If this object holds a NULL pointer, the return value is NULL. 326 // If this object holds a NULL pointer, the return value is NULL.
224 // After this operation, this object will hold a NULL pointer, 327 // After this operation, this object will hold a NULL pointer,
225 // and will not own the object any more. 328 // and will not own the object any more.
226 C* release() WARN_UNUSED_RESULT { 329 C* release() WARN_UNUSED_RESULT {
227 C* retVal = ptr_; 330 return impl_.release();
228 ptr_ = NULL;
229 return retVal;
230 } 331 }
231 332
232 template <typename PassAsType> 333 template <typename PassAsType, typename DeleteAsType = base::DefaultDeleter<Pa ssAsType> >
233 scoped_ptr<PassAsType> PassAs() { 334 scoped_ptr<PassAsType, DeleteAsType> PassAs() {
234 return scoped_ptr<PassAsType>(release()); 335 return scoped_ptr<PassAsType, DeleteAsType>(release());
235 } 336 }
236 337
237 private: 338 private:
238 C* ptr_; 339 base::internal::scoped_ptr_impl<C, D> impl_;
239 340
240 // Forbid comparison of scoped_ptr types. If C2 != C, it totally doesn't 341 // Forbid comparison of scoped_ptr types. If C2 != C, it totally doesn't
241 // make sense, and if C2 == C, it still doesn't make sense because you should 342 // make sense, and if C2 == C, it still doesn't make sense because you should
242 // never have the same object owned by two different scoped_ptrs. 343 // never have the same object owned by two different scoped_ptrs.
243 template <class C2> bool operator==(scoped_ptr<C2> const& p2) const; 344 template <class C2> bool operator==(scoped_ptr<C2> const& p2) const;
244 template <class C2> bool operator!=(scoped_ptr<C2> const& p2) const; 345 template <class C2> bool operator!=(scoped_ptr<C2> const& p2) const;
245 346
246 }; 347 };
247 348
248 // Free functions 349 // Free functions
249 template <class C> 350 template <class C, class D>
250 void swap(scoped_ptr<C>& p1, scoped_ptr<C>& p2) { 351 void swap(scoped_ptr<C, D>& p1, scoped_ptr<C, D>& p2) {
251 p1.swap(p2); 352 p1.swap(p2);
252 } 353 }
253 354
254 template <class C> 355 template <class C, class D>
255 bool operator==(C* p1, const scoped_ptr<C>& p2) { 356 bool operator==(C* p1, const scoped_ptr<C, D>& p2) {
256 return p1 == p2.get(); 357 return p1 == p2.get();
257 } 358 }
258 359
259 template <class C> 360 template <class C, class D>
260 bool operator!=(C* p1, const scoped_ptr<C>& p2) { 361 bool operator!=(C* p1, const scoped_ptr<C, D>& p2) {
261 return p1 != p2.get(); 362 return p1 != p2.get();
262 } 363 }
263 364
264 // scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate 365 // scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate
265 // with new [] and the destructor deletes objects with delete []. 366 // with new [] and the destructor deletes objects with delete [].
266 // 367 //
267 // As with scoped_ptr<C>, a scoped_array<C> either points to an object 368 // As with scoped_ptr<C>, a scoped_array<C> either points to an object
268 // or is NULL. A scoped_array<C> owns the object that it points to. 369 // or is NULL. A scoped_array<C> owns the object that it points to.
269 // scoped_array<T> is thread-compatible, and once you index into it, 370 // scoped_array<T> is thread-compatible, and once you index into it,
270 // the returned objects have only the thread safety guarantees of T. 371 // the returned objects have only the thread safety guarantees of T.
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after
515 616
516 // A function to convert T* into scoped_ptr<T> 617 // A function to convert T* into scoped_ptr<T>
517 // Doing e.g. make_scoped_ptr(new FooBarBaz<type>(arg)) is a shorter notation 618 // Doing e.g. make_scoped_ptr(new FooBarBaz<type>(arg)) is a shorter notation
518 // for scoped_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg)) 619 // for scoped_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
519 template <typename T> 620 template <typename T>
520 scoped_ptr<T> make_scoped_ptr(T* ptr) { 621 scoped_ptr<T> make_scoped_ptr(T* ptr) {
521 return scoped_ptr<T>(ptr); 622 return scoped_ptr<T>(ptr);
522 } 623 }
523 624
524 #endif // BASE_MEMORY_SCOPED_PTR_H_ 625 #endif // BASE_MEMORY_SCOPED_PTR_H_
OLDNEW
« no previous file with comments | « no previous file | base/memory/scoped_ptr_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698