OLD | NEW |
---|---|
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 a | 5 // Scopers help you manage ownership of a pointer, helping you easily manage a |
6 // pointer within a scope, and automatically destroying the pointer at the end | 6 // pointer within a scope, and automatically destroying the pointer at the end |
7 // of a scope. There are two main classes you will use, which correspond to the | 7 // of a scope. There are two main classes you will use, which correspond to the |
8 // operators new/delete and new[]/delete[]. | 8 // operators new/delete and new[]/delete[]. |
9 // | 9 // |
10 // Example usage (scoped_ptr<T>): | 10 // Example usage (scoped_ptr<T>): |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
79 | 79 |
80 // This is an implementation designed to match the anticipated future TR2 | 80 // This is an implementation designed to match the anticipated future TR2 |
81 // implementation of the scoped_ptr class. | 81 // implementation of the scoped_ptr class. |
82 | 82 |
83 #include <assert.h> | 83 #include <assert.h> |
84 #include <stddef.h> | 84 #include <stddef.h> |
85 #include <stdlib.h> | 85 #include <stdlib.h> |
86 | 86 |
87 #include <iosfwd> | 87 #include <iosfwd> |
88 #include <memory> | 88 #include <memory> |
89 #include <type_traits> | |
89 #include <utility> | 90 #include <utility> |
90 | 91 |
91 #include "base/basictypes.h" | 92 #include "base/basictypes.h" |
92 #include "base/compiler_specific.h" | 93 #include "base/compiler_specific.h" |
93 #include "base/move.h" | 94 #include "base/move.h" |
94 #include "base/template_util.h" | 95 #include "base/template_util.h" |
95 | 96 |
96 namespace base { | 97 namespace base { |
97 | 98 |
98 namespace subtle { | 99 namespace subtle { |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
251 | 252 |
252 // Constructor. Takes ownership of p. | 253 // Constructor. Takes ownership of p. |
253 explicit scoped_ptr(element_type* p) : impl_(p) {} | 254 explicit scoped_ptr(element_type* p) : impl_(p) {} |
254 | 255 |
255 // Constructor. Allows initialization of a stateful deleter. | 256 // Constructor. Allows initialization of a stateful deleter. |
256 scoped_ptr(element_type* p, const D& d) : impl_(p, d) {} | 257 scoped_ptr(element_type* p, const D& d) : impl_(p, d) {} |
257 | 258 |
258 // Constructor. Allows construction from a nullptr. | 259 // Constructor. Allows construction from a nullptr. |
259 scoped_ptr(std::nullptr_t) : impl_(nullptr) {} | 260 scoped_ptr(std::nullptr_t) : impl_(nullptr) {} |
260 | 261 |
261 // Constructor. Allows construction from a scoped_ptr rvalue for a | 262 // Move constructor. |
263 // | |
264 // IMPLEMENTATION NOTE: Clang requires a move constructor to be defined (and | |
265 // not just the conversion constructor) in order to warn on pessimizing moves. | |
266 // The requirements for the move constructor are specified in C++11 | |
267 // 20.7.1.2.1.15-17, which has some subtleties around reference deleters. As | |
268 // we | |
vmpstr
2015/11/19 21:00:24
<_<
danakj
2015/11/19 21:03:36
wrapping broke
dcheng
2015/11/19 21:26:04
Oops.
| |
269 // don't support reference (or move-only) deleters, the post conditions are | |
270 // trivially true: we always copy construct the deleter from other's deleter. | |
271 scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {} | |
272 | |
273 // Conversion constructor. Allows construction from a scoped_ptr rvalue for a | |
262 // convertible type and deleter. | 274 // convertible type and deleter. |
263 // | 275 // |
264 // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this constructor distinct | 276 // IMPLEMENTATION NOTE: C++ 20.7.1.2.1.19 requires this constructor to only |
265 // from the normal move constructor. By C++11 20.7.1.2.1.21, this constructor | 277 // participate in overload resolution if all the following are true: |
266 // has different post-conditions if D is a reference type. Since this | 278 // - U is implicitly convertible to T: this is important for 2 reasons: |
267 // implementation does not support deleters with reference type, | 279 // 1. So type traits don't incorrectly return true, e.g. |
268 // we do not need a separate move constructor allowing us to avoid one | 280 // std::is_convertible<scoped_ptr<Base>, scoped_ptr<Derived>>::value |
269 // use of SFINAE. You only need to care about this if you modify the | 281 // should be false. |
270 // implementation of scoped_ptr. | 282 // 2. To make sure code like this compiles: |
271 template <typename U, typename V> | 283 // void F(scoped_ptr<int>); |
272 scoped_ptr(scoped_ptr<U, V>&& other) | 284 // void F(scoped_ptr<Base>); |
273 : impl_(&other.impl_) { | 285 // // ambiguous since both conversion constructors match. |
danakj
2015/11/19 21:03:36
nit: capital A
dcheng
2015/11/19 21:26:04
Done.
| |
274 COMPILE_ASSERT(!base::is_array<U>::value, U_cannot_be_an_array); | 286 // F(scoped_ptr<Derived>()); |
287 // - U is not an array type: to prevent conversions from scoped_ptr<T[]> to | |
288 // scoped_ptr<T>. | |
289 // - D is a reference type and E is the same type, or D is not a reference | |
290 // type and E is implicitly convertible to D: again, we don't support | |
291 // reference deleters, so we only worry about the latter requirement. | |
292 template <typename U, | |
293 typename E, | |
dcheng
2015/11/19 20:49:10
I renamed the second template parameter from V to
danakj
2015/11/19 21:03:36
sgtm
| |
294 typename = typename std::enable_if< | |
295 !std::is_array<U>::value && | |
296 std::is_convertible<typename scoped_ptr<U, E>::pointer_type, | |
297 pointer_type>::value && | |
298 std::is_convertible<E, D>::value>::type> | |
299 scoped_ptr(scoped_ptr<U, E>&& other) | |
300 : impl_(&other.impl_) {} | |
301 | |
302 // operator=. | |
303 // | |
304 // IMPLEMENTATION NOTE: Unlike the move constructor, Clang does not appear to | |
305 // require a move assignment operator to trigger the pessimizing move warning: | |
306 // in this case, the warning triggers when moving a temporary. For consistency | |
307 // with the move constructor, we define it anyway. C++11 20.7.1.2.3.1-3 | |
308 // defines several requirements around this: like the move constructor, the | |
309 // requirements are simplified by the fact that we don't support move-only or | |
310 // reference deleters. | |
311 scoped_ptr& operator=(scoped_ptr&& rhs) { | |
312 impl_.TakeState(&rhs.impl_); | |
313 return *this; | |
275 } | 314 } |
276 | 315 |
277 // operator=. Allows assignment from a scoped_ptr rvalue for a convertible | 316 // operator=. Allows assignment from a scoped_ptr rvalue for a convertible |
278 // type and deleter. | 317 // type and deleter. |
279 // | 318 // |
280 // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from | 319 // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from |
281 // the normal move assignment operator. By C++11 20.7.1.2.3.4, this templated | 320 // the normal move assignment operator. C++11 20.7.1.2.3.4-7 contains the |
282 // form has different requirements on for move-only Deleters. Since this | 321 // requirement for this operator, but like the conversion constructor, the |
283 // implementation does not support move-only Deleters, we do not need a | 322 // requirements are greatly simplified by not supporting move-only or |
284 // separate move assignment operator allowing us to avoid one use of SFINAE. | 323 // reference deleters. |
285 // You only need to care about this if you modify the implementation of | 324 template <typename U, |
286 // scoped_ptr. | 325 typename E, |
287 template <typename U, typename V> | 326 typename = typename std::enable_if< |
vmpstr
2015/11/19 21:00:24
So, to elaborate on what I was saying earlier, you
dcheng
2015/11/19 21:26:04
This is the only way I could get it to compile:
te
vmpstr
2015/11/19 21:28:41
My guess is you didn't put the ", int" part in the
| |
288 scoped_ptr& operator=(scoped_ptr<U, V>&& rhs) { | 327 !std::is_array<U>::value && |
289 COMPILE_ASSERT(!base::is_array<U>::value, U_cannot_be_an_array); | 328 std::is_convertible<typename scoped_ptr<U, E>::pointer_type, |
329 pointer_type>::value && | |
330 std::is_convertible<E, D>::value>::type> | |
331 scoped_ptr& operator=(scoped_ptr<U, E>&& rhs) { | |
290 impl_.TakeState(&rhs.impl_); | 332 impl_.TakeState(&rhs.impl_); |
291 return *this; | 333 return *this; |
292 } | 334 } |
293 | 335 |
294 // operator=. Allows assignment from a nullptr. Deletes the currently owned | 336 // operator=. Allows assignment from a nullptr. Deletes the currently owned |
295 // object, if any. | 337 // object, if any. |
296 scoped_ptr& operator=(std::nullptr_t) { | 338 scoped_ptr& operator=(std::nullptr_t) { |
297 reset(); | 339 reset(); |
298 return *this; | 340 return *this; |
299 } | 341 } |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
355 // Forbidden for API compatibility with std::unique_ptr. | 397 // Forbidden for API compatibility with std::unique_ptr. |
356 explicit scoped_ptr(int disallow_construction_from_null); | 398 explicit scoped_ptr(int disallow_construction_from_null); |
357 }; | 399 }; |
358 | 400 |
359 template <class T, class D> | 401 template <class T, class D> |
360 class scoped_ptr<T[], D> { | 402 class scoped_ptr<T[], D> { |
361 MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_ptr) | 403 MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_ptr) |
362 | 404 |
363 public: | 405 public: |
364 // The element and deleter types. | 406 // The element and deleter types. |
365 typedef T element_type; | 407 using element_type = T; |
366 typedef D deleter_type; | 408 using pointer_type = element_type*; |
dcheng
2015/11/19 20:49:10
This is for consistency, but probably not needed,
vmpstr
2015/11/19 21:00:24
FWIW, I think reading
std::is_convertible<U*, T*>
danakj
2015/11/19 21:03:36
unique_ptr has ::pointer, not pointer_type. and it
dcheng
2015/11/19 21:26:04
Given vmpstr@'s feedback and the fact that our poi
| |
409 using deleter_type = D; | |
367 | 410 |
368 // Constructor. Defaults to initializing with nullptr. | 411 // Constructor. Defaults to initializing with nullptr. |
369 scoped_ptr() : impl_(nullptr) {} | 412 scoped_ptr() : impl_(nullptr) {} |
370 | 413 |
371 // Constructor. Stores the given array. Note that the argument's type | 414 // Constructor. Stores the given array. Note that the argument's type |
372 // must exactly match T*. In particular: | 415 // must exactly match T*. In particular: |
373 // - it cannot be a pointer to a type derived from T, because it is | 416 // - it cannot be a pointer to a type derived from T, because it is |
374 // inherently unsafe in the general case to access an array through a | 417 // inherently unsafe in the general case to access an array through a |
375 // pointer whose dynamic type does not match its static type (eg., if | 418 // pointer whose dynamic type does not match its static type (eg., if |
376 // T and the derived types had different sizes access would be | 419 // T and the derived types had different sizes access would be |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
551 scoped_ptr<T> make_scoped_ptr(T* ptr) { | 594 scoped_ptr<T> make_scoped_ptr(T* ptr) { |
552 return scoped_ptr<T>(ptr); | 595 return scoped_ptr<T>(ptr); |
553 } | 596 } |
554 | 597 |
555 template <typename T> | 598 template <typename T> |
556 std::ostream& operator<<(std::ostream& out, const scoped_ptr<T>& p) { | 599 std::ostream& operator<<(std::ostream& out, const scoped_ptr<T>& p) { |
557 return out << p.get(); | 600 return out << p.get(); |
558 } | 601 } |
559 | 602 |
560 #endif // BASE_MEMORY_SCOPED_PTR_H_ | 603 #endif // BASE_MEMORY_SCOPED_PTR_H_ |
OLD | NEW |