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
3 // found in the LICENSE file.
5 #include "base/memory/scoped_ptr.h"
7 #include "base/basictypes.h"
9 #include "base/callback.h"
10 #include "testing/gtest/include/gtest/gtest.h"
14 // Used to test depth subtyping.
15 class ConDecLoggerParent
{
17 virtual ~ConDecLoggerParent() {}
19 virtual void SetPtr(int* ptr
) = 0;
21 virtual int SomeMeth(int x
) const = 0;
24 class ConDecLogger
: public ConDecLoggerParent
{
26 ConDecLogger() : ptr_(NULL
) { }
27 explicit ConDecLogger(int* ptr
) { SetPtr(ptr
); }
28 ~ConDecLogger() override
{ --*ptr_
; }
30 void SetPtr(int* ptr
) override
{
35 int SomeMeth(int x
) const override
{ return x
; }
40 DISALLOW_COPY_AND_ASSIGN(ConDecLogger
);
43 struct CountingDeleter
{
44 explicit CountingDeleter(int* count
) : count_(count
) {}
45 inline void operator()(double* ptr
) const {
51 // Used to test assignment of convertible deleters.
52 struct CountingDeleterChild
: public CountingDeleter
{
53 explicit CountingDeleterChild(int* count
) : CountingDeleter(count
) {}
56 class OverloadedNewAndDelete
{
58 void* operator new(size_t size
) {
63 void operator delete(void* ptr
) {
68 static void ResetCounters() {
73 static int new_count() { return g_new_count
; }
74 static int delete_count() { return g_delete_count
; }
77 static int g_new_count
;
78 static int g_delete_count
;
81 int OverloadedNewAndDelete::g_new_count
= 0;
82 int OverloadedNewAndDelete::g_delete_count
= 0;
84 scoped_ptr
<ConDecLogger
> PassThru(scoped_ptr
<ConDecLogger
> logger
) {
88 void GrabAndDrop(scoped_ptr
<ConDecLogger
> logger
) {
91 // Do not delete this function! It's existence is to test that you can
92 // return a temporarily constructed version of the scoper.
93 scoped_ptr
<ConDecLogger
> TestReturnOfType(int* constructed
) {
94 return scoped_ptr
<ConDecLogger
>(new ConDecLogger(constructed
));
99 TEST(ScopedPtrTest
, ScopedPtr
) {
102 // Ensure size of scoped_ptr<> doesn't increase unexpectedly.
103 COMPILE_ASSERT(sizeof(int*) >= sizeof(scoped_ptr
<int>),
104 scoped_ptr_larger_than_raw_ptr
);
107 scoped_ptr
<ConDecLogger
> scoper(new ConDecLogger(&constructed
));
108 EXPECT_EQ(1, constructed
);
109 EXPECT_TRUE(scoper
.get());
111 EXPECT_EQ(10, scoper
->SomeMeth(10));
112 EXPECT_EQ(10, scoper
.get()->SomeMeth(10));
113 EXPECT_EQ(10, (*scoper
).SomeMeth(10));
115 EXPECT_EQ(0, constructed
);
117 // Test reset() and release()
119 scoped_ptr
<ConDecLogger
> scoper(new ConDecLogger(&constructed
));
120 EXPECT_EQ(1, constructed
);
121 EXPECT_TRUE(scoper
.get());
123 scoper
.reset(new ConDecLogger(&constructed
));
124 EXPECT_EQ(1, constructed
);
125 EXPECT_TRUE(scoper
.get());
128 EXPECT_EQ(0, constructed
);
129 EXPECT_FALSE(scoper
.get());
131 scoper
.reset(new ConDecLogger(&constructed
));
132 EXPECT_EQ(1, constructed
);
133 EXPECT_TRUE(scoper
.get());
135 ConDecLogger
* take
= scoper
.release();
136 EXPECT_EQ(1, constructed
);
137 EXPECT_FALSE(scoper
.get());
139 EXPECT_EQ(0, constructed
);
141 scoper
.reset(new ConDecLogger(&constructed
));
142 EXPECT_EQ(1, constructed
);
143 EXPECT_TRUE(scoper
.get());
145 EXPECT_EQ(0, constructed
);
147 // Test swap(), == and !=
149 scoped_ptr
<ConDecLogger
> scoper1
;
150 scoped_ptr
<ConDecLogger
> scoper2
;
151 EXPECT_TRUE(scoper1
== scoper2
.get());
152 EXPECT_FALSE(scoper1
!= scoper2
.get());
154 ConDecLogger
* logger
= new ConDecLogger(&constructed
);
155 scoper1
.reset(logger
);
156 EXPECT_EQ(logger
, scoper1
.get());
157 EXPECT_FALSE(scoper2
.get());
158 EXPECT_FALSE(scoper1
== scoper2
.get());
159 EXPECT_TRUE(scoper1
!= scoper2
.get());
161 scoper2
.swap(scoper1
);
162 EXPECT_EQ(logger
, scoper2
.get());
163 EXPECT_FALSE(scoper1
.get());
164 EXPECT_FALSE(scoper1
== scoper2
.get());
165 EXPECT_TRUE(scoper1
!= scoper2
.get());
167 EXPECT_EQ(0, constructed
);
170 TEST(ScopedPtrTest
, ScopedPtrDepthSubtyping
) {
173 // Test construction from a scoped_ptr to a derived class.
175 scoped_ptr
<ConDecLogger
> scoper(new ConDecLogger(&constructed
));
176 EXPECT_EQ(1, constructed
);
177 EXPECT_TRUE(scoper
.get());
179 scoped_ptr
<ConDecLoggerParent
> scoper_parent(scoper
.Pass());
180 EXPECT_EQ(1, constructed
);
181 EXPECT_TRUE(scoper_parent
.get());
182 EXPECT_FALSE(scoper
.get());
184 EXPECT_EQ(10, scoper_parent
->SomeMeth(10));
185 EXPECT_EQ(10, scoper_parent
.get()->SomeMeth(10));
186 EXPECT_EQ(10, (*scoper_parent
).SomeMeth(10));
188 EXPECT_EQ(0, constructed
);
190 // Test assignment from a scoped_ptr to a derived class.
192 scoped_ptr
<ConDecLogger
> scoper(new ConDecLogger(&constructed
));
193 EXPECT_EQ(1, constructed
);
194 EXPECT_TRUE(scoper
.get());
196 scoped_ptr
<ConDecLoggerParent
> scoper_parent
;
197 scoper_parent
= scoper
.Pass();
198 EXPECT_EQ(1, constructed
);
199 EXPECT_TRUE(scoper_parent
.get());
200 EXPECT_FALSE(scoper
.get());
202 EXPECT_EQ(0, constructed
);
204 // Test construction of a scoped_ptr with an additional const annotation.
206 scoped_ptr
<ConDecLogger
> scoper(new ConDecLogger(&constructed
));
207 EXPECT_EQ(1, constructed
);
208 EXPECT_TRUE(scoper
.get());
210 scoped_ptr
<const ConDecLogger
> scoper_const(scoper
.Pass());
211 EXPECT_EQ(1, constructed
);
212 EXPECT_TRUE(scoper_const
.get());
213 EXPECT_FALSE(scoper
.get());
215 EXPECT_EQ(10, scoper_const
->SomeMeth(10));
216 EXPECT_EQ(10, scoper_const
.get()->SomeMeth(10));
217 EXPECT_EQ(10, (*scoper_const
).SomeMeth(10));
219 EXPECT_EQ(0, constructed
);
221 // Test assignment to a scoped_ptr with an additional const annotation.
223 scoped_ptr
<ConDecLogger
> scoper(new ConDecLogger(&constructed
));
224 EXPECT_EQ(1, constructed
);
225 EXPECT_TRUE(scoper
.get());
227 scoped_ptr
<const ConDecLogger
> scoper_const
;
228 scoper_const
= scoper
.Pass();
229 EXPECT_EQ(1, constructed
);
230 EXPECT_TRUE(scoper_const
.get());
231 EXPECT_FALSE(scoper
.get());
233 EXPECT_EQ(0, constructed
);
235 // Test assignment to a scoped_ptr deleter of parent type.
237 // Custom deleters never touch these value.
238 double dummy_value
, dummy_value2
;
240 int alternate_deletes
= 0;
241 scoped_ptr
<double, CountingDeleter
> scoper(&dummy_value
,
242 CountingDeleter(&deletes
));
243 scoped_ptr
<double, CountingDeleterChild
> scoper_child(
244 &dummy_value2
, CountingDeleterChild(&alternate_deletes
));
247 EXPECT_TRUE(scoper_child
);
248 EXPECT_EQ(0, deletes
);
249 EXPECT_EQ(0, alternate_deletes
);
251 // Test this compiles and correctly overwrites the deleter state.
252 scoper
= scoper_child
.Pass();
254 EXPECT_FALSE(scoper_child
);
255 EXPECT_EQ(1, deletes
);
256 EXPECT_EQ(0, alternate_deletes
);
259 EXPECT_FALSE(scoper
);
260 EXPECT_FALSE(scoper_child
);
261 EXPECT_EQ(1, deletes
);
262 EXPECT_EQ(1, alternate_deletes
);
264 scoper_child
.reset(&dummy_value
);
265 EXPECT_TRUE(scoper_child
);
266 EXPECT_EQ(1, deletes
);
267 EXPECT_EQ(1, alternate_deletes
);
268 scoped_ptr
<double, CountingDeleter
> scoper_construct(scoper_child
.Pass());
269 EXPECT_TRUE(scoper_construct
);
270 EXPECT_FALSE(scoper_child
);
271 EXPECT_EQ(1, deletes
);
272 EXPECT_EQ(1, alternate_deletes
);
274 scoper_construct
.reset();
275 EXPECT_EQ(1, deletes
);
276 EXPECT_EQ(2, alternate_deletes
);
280 TEST(ScopedPtrTest
, ScopedPtrWithArray
) {
281 static const int kNumLoggers
= 12;
286 scoped_ptr
<ConDecLogger
[]> scoper(new ConDecLogger
[kNumLoggers
]);
288 EXPECT_EQ(&scoper
[0], scoper
.get());
289 for (int i
= 0; i
< kNumLoggers
; ++i
) {
290 scoper
[i
].SetPtr(&constructed
);
292 EXPECT_EQ(12, constructed
);
294 EXPECT_EQ(10, scoper
.get()->SomeMeth(10));
295 EXPECT_EQ(10, scoper
[2].SomeMeth(10));
297 EXPECT_EQ(0, constructed
);
299 // Test reset() and release()
301 scoped_ptr
<ConDecLogger
[]> scoper
;
302 EXPECT_FALSE(scoper
.get());
303 EXPECT_FALSE(scoper
.release());
304 EXPECT_FALSE(scoper
.get());
306 EXPECT_FALSE(scoper
.get());
308 scoper
.reset(new ConDecLogger
[kNumLoggers
]);
309 for (int i
= 0; i
< kNumLoggers
; ++i
) {
310 scoper
[i
].SetPtr(&constructed
);
312 EXPECT_EQ(12, constructed
);
314 EXPECT_EQ(0, constructed
);
316 scoper
.reset(new ConDecLogger
[kNumLoggers
]);
317 for (int i
= 0; i
< kNumLoggers
; ++i
) {
318 scoper
[i
].SetPtr(&constructed
);
320 EXPECT_EQ(12, constructed
);
321 ConDecLogger
* ptr
= scoper
.release();
322 EXPECT_EQ(12, constructed
);
324 EXPECT_EQ(0, constructed
);
326 EXPECT_EQ(0, constructed
);
328 // Test swap(), ==, !=, and type-safe Boolean.
330 scoped_ptr
<ConDecLogger
[]> scoper1
;
331 scoped_ptr
<ConDecLogger
[]> scoper2
;
332 EXPECT_TRUE(scoper1
== scoper2
.get());
333 EXPECT_FALSE(scoper1
!= scoper2
.get());
335 ConDecLogger
* loggers
= new ConDecLogger
[kNumLoggers
];
336 for (int i
= 0; i
< kNumLoggers
; ++i
) {
337 loggers
[i
].SetPtr(&constructed
);
339 scoper1
.reset(loggers
);
340 EXPECT_TRUE(scoper1
);
341 EXPECT_EQ(loggers
, scoper1
.get());
342 EXPECT_FALSE(scoper2
);
343 EXPECT_FALSE(scoper2
.get());
344 EXPECT_FALSE(scoper1
== scoper2
.get());
345 EXPECT_TRUE(scoper1
!= scoper2
.get());
347 scoper2
.swap(scoper1
);
348 EXPECT_EQ(loggers
, scoper2
.get());
349 EXPECT_FALSE(scoper1
.get());
350 EXPECT_FALSE(scoper1
== scoper2
.get());
351 EXPECT_TRUE(scoper1
!= scoper2
.get());
353 EXPECT_EQ(0, constructed
);
356 ConDecLogger
* loggers
= new ConDecLogger
[kNumLoggers
];
357 scoped_ptr
<ConDecLogger
[]> scoper(loggers
);
359 for (int i
= 0; i
< kNumLoggers
; ++i
) {
360 scoper
[i
].SetPtr(&constructed
);
362 EXPECT_EQ(kNumLoggers
, constructed
);
364 // Test Pass() with constructor;
365 scoped_ptr
<ConDecLogger
[]> scoper2(scoper
.Pass());
366 EXPECT_EQ(kNumLoggers
, constructed
);
368 // Test Pass() with assignment;
369 scoped_ptr
<ConDecLogger
[]> scoper3
;
370 scoper3
= scoper2
.Pass();
371 EXPECT_EQ(kNumLoggers
, constructed
);
372 EXPECT_FALSE(scoper
);
373 EXPECT_FALSE(scoper2
);
374 EXPECT_TRUE(scoper3
);
376 EXPECT_EQ(0, constructed
);
379 TEST(ScopedPtrTest
, PassBehavior
) {
382 ConDecLogger
* logger
= new ConDecLogger(&constructed
);
383 scoped_ptr
<ConDecLogger
> scoper(logger
);
384 EXPECT_EQ(1, constructed
);
386 // Test Pass() with constructor;
387 scoped_ptr
<ConDecLogger
> scoper2(scoper
.Pass());
388 EXPECT_EQ(1, constructed
);
390 // Test Pass() with assignment;
391 scoped_ptr
<ConDecLogger
> scoper3
;
392 scoper3
= scoper2
.Pass();
393 EXPECT_EQ(1, constructed
);
394 EXPECT_FALSE(scoper
.get());
395 EXPECT_FALSE(scoper2
.get());
396 EXPECT_TRUE(scoper3
.get());
399 // Test uncaught Pass() does not have side effects.
401 ConDecLogger
* logger
= new ConDecLogger(&constructed
);
402 scoped_ptr
<ConDecLogger
> scoper(logger
);
403 EXPECT_EQ(1, constructed
);
405 // Should auto-destruct logger by end of scope.
406 scoped_ptr
<ConDecLogger
>&& rvalue
= scoper
.Pass();
407 // The Pass() function mimics std::move(), which does not have side-effects.
408 EXPECT_TRUE(scoper
.get());
411 EXPECT_EQ(0, constructed
);
413 // Test that passing to function which does nothing does not leak.
415 ConDecLogger
* logger
= new ConDecLogger(&constructed
);
416 scoped_ptr
<ConDecLogger
> scoper(logger
);
417 EXPECT_EQ(1, constructed
);
419 // Should auto-destruct logger by end of scope.
420 GrabAndDrop(scoper
.Pass());
421 EXPECT_FALSE(scoper
.get());
423 EXPECT_EQ(0, constructed
);
426 TEST(ScopedPtrTest
, ReturnTypeBehavior
) {
429 // Test that we can return a scoped_ptr.
431 ConDecLogger
* logger
= new ConDecLogger(&constructed
);
432 scoped_ptr
<ConDecLogger
> scoper(logger
);
433 EXPECT_EQ(1, constructed
);
435 PassThru(scoper
.Pass());
436 EXPECT_FALSE(scoper
.get());
438 EXPECT_EQ(0, constructed
);
440 // Test uncaught return type not leak.
442 ConDecLogger
* logger
= new ConDecLogger(&constructed
);
443 scoped_ptr
<ConDecLogger
> scoper(logger
);
444 EXPECT_EQ(1, constructed
);
446 // Should auto-destruct logger by end of scope.
447 PassThru(scoper
.Pass());
448 EXPECT_FALSE(scoper
.get());
450 EXPECT_EQ(0, constructed
);
452 // Call TestReturnOfType() so the compiler doesn't warn for an unused
455 TestReturnOfType(&constructed
);
457 EXPECT_EQ(0, constructed
);
460 TEST(ScopedPtrTest
, CustomDeleter
) {
461 double dummy_value
; // Custom deleter never touches this value.
463 int alternate_deletes
= 0;
465 // Normal delete support.
468 scoped_ptr
<double, CountingDeleter
> scoper(&dummy_value
,
469 CountingDeleter(&deletes
));
470 EXPECT_EQ(0, deletes
);
471 EXPECT_TRUE(scoper
.get());
473 EXPECT_EQ(1, deletes
);
475 // Test reset() and release().
478 scoped_ptr
<double, CountingDeleter
> scoper(NULL
,
479 CountingDeleter(&deletes
));
480 EXPECT_FALSE(scoper
.get());
481 EXPECT_FALSE(scoper
.release());
482 EXPECT_FALSE(scoper
.get());
484 EXPECT_FALSE(scoper
.get());
485 EXPECT_EQ(0, deletes
);
487 scoper
.reset(&dummy_value
);
489 EXPECT_EQ(1, deletes
);
491 scoper
.reset(&dummy_value
);
492 EXPECT_EQ(&dummy_value
, scoper
.release());
494 EXPECT_EQ(1, deletes
);
496 // Test get_deleter().
498 alternate_deletes
= 0;
500 scoped_ptr
<double, CountingDeleter
> scoper(&dummy_value
,
501 CountingDeleter(&deletes
));
502 // Call deleter manually.
503 EXPECT_EQ(0, deletes
);
504 scoper
.get_deleter()(&dummy_value
);
505 EXPECT_EQ(1, deletes
);
507 // Deleter is still there after reset.
509 EXPECT_EQ(2, deletes
);
510 scoper
.get_deleter()(&dummy_value
);
511 EXPECT_EQ(3, deletes
);
513 // Deleter can be assigned into (matches C++11 unique_ptr<> spec).
514 scoper
.get_deleter() = CountingDeleter(&alternate_deletes
);
515 scoper
.reset(&dummy_value
);
516 EXPECT_EQ(0, alternate_deletes
);
519 EXPECT_EQ(3, deletes
);
520 EXPECT_EQ(1, alternate_deletes
);
522 // Test operator= deleter support.
524 alternate_deletes
= 0;
527 scoped_ptr
<double, CountingDeleter
> scoper(&dummy_value
,
528 CountingDeleter(&deletes
));
529 scoped_ptr
<double, CountingDeleter
> scoper2(
531 CountingDeleter(&alternate_deletes
));
532 EXPECT_EQ(0, deletes
);
533 EXPECT_EQ(0, alternate_deletes
);
535 // Pass the second deleter through a constructor and an operator=. Then
536 // reinitialize the empty scopers to ensure that each one is deleting
538 scoped_ptr
<double, CountingDeleter
> scoper3(scoper2
.Pass());
539 scoper
= scoper3
.Pass();
540 EXPECT_EQ(1, deletes
);
542 scoper2
.reset(&dummy_value2
);
543 scoper3
.reset(&dummy_value2
);
544 EXPECT_EQ(0, alternate_deletes
);
547 EXPECT_EQ(1, deletes
);
548 EXPECT_EQ(3, alternate_deletes
);
550 // Test swap(), ==, !=, and type-safe Boolean.
552 scoped_ptr
<double, CountingDeleter
> scoper1(NULL
,
553 CountingDeleter(&deletes
));
554 scoped_ptr
<double, CountingDeleter
> scoper2(NULL
,
555 CountingDeleter(&deletes
));
556 EXPECT_TRUE(scoper1
== scoper2
.get());
557 EXPECT_FALSE(scoper1
!= scoper2
.get());
559 scoper1
.reset(&dummy_value
);
560 EXPECT_TRUE(scoper1
);
561 EXPECT_EQ(&dummy_value
, scoper1
.get());
562 EXPECT_FALSE(scoper2
);
563 EXPECT_FALSE(scoper2
.get());
564 EXPECT_FALSE(scoper1
== scoper2
.get());
565 EXPECT_TRUE(scoper1
!= scoper2
.get());
567 scoper2
.swap(scoper1
);
568 EXPECT_EQ(&dummy_value
, scoper2
.get());
569 EXPECT_FALSE(scoper1
.get());
570 EXPECT_FALSE(scoper1
== scoper2
.get());
571 EXPECT_TRUE(scoper1
!= scoper2
.get());
575 // Sanity check test for overloaded new and delete operators. Does not do full
576 // coverage of reset/release/Pass() operations as that is redundant with the
578 TEST(ScopedPtrTest
, OverloadedNewAndDelete
) {
580 OverloadedNewAndDelete::ResetCounters();
581 scoped_ptr
<OverloadedNewAndDelete
> scoper(new OverloadedNewAndDelete());
582 EXPECT_TRUE(scoper
.get());
584 scoped_ptr
<OverloadedNewAndDelete
> scoper2(scoper
.Pass());
586 EXPECT_EQ(1, OverloadedNewAndDelete::delete_count());
587 EXPECT_EQ(1, OverloadedNewAndDelete::new_count());
590 scoped_ptr
<int> NullIntReturn() {
594 TEST(ScopedPtrTest
, Nullptr
) {
595 scoped_ptr
<int> scoper1(nullptr);
596 scoped_ptr
<int> scoper2(new int);
598 scoped_ptr
<int> scoper3(NullIntReturn());
599 scoped_ptr
<int> scoper4
= NullIntReturn();
600 EXPECT_EQ(nullptr, scoper1
.get());
601 EXPECT_EQ(nullptr, scoper2
.get());
602 EXPECT_EQ(nullptr, scoper3
.get());
603 EXPECT_EQ(nullptr, scoper4
.get());
606 scoped_ptr
<int[]> NullIntArrayReturn() {
610 TEST(ScopedPtrTest
, NullptrArray
) {
611 scoped_ptr
<int[]> scoper1(nullptr);
612 scoped_ptr
<int[]> scoper2(new int[3]);
614 scoped_ptr
<int[]> scoper3(NullIntArrayReturn());
615 scoped_ptr
<int[]> scoper4
= NullIntArrayReturn();
616 EXPECT_EQ(nullptr, scoper1
.get());
617 EXPECT_EQ(nullptr, scoper2
.get());
618 EXPECT_EQ(nullptr, scoper3
.get());
619 EXPECT_EQ(nullptr, scoper4
.get());
623 class Sub
: public Super
{};
625 scoped_ptr
<Sub
> SubClassReturn() {
626 return make_scoped_ptr(new Sub
);
629 TEST(ScopedPtrTest
, Conversion
) {
630 scoped_ptr
<Sub
> sub1(new Sub
);
631 scoped_ptr
<Sub
> sub2(new Sub
);
633 // Upcast with Pass() works.
634 scoped_ptr
<Super
> super1
= sub1
.Pass();
635 super1
= sub2
.Pass();
637 // Upcast with an rvalue works.
638 scoped_ptr
<Super
> super2
= SubClassReturn();
639 super2
= SubClassReturn();
642 // Android death tests don't work properly with assert(). Yay.
643 #if !defined(NDEBUG) && defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
644 TEST(ScopedPtrTest
, SelfResetAbortsWithDefaultDeleter
) {
645 scoped_ptr
<int> x(new int);
646 EXPECT_DEATH(x
.reset(x
.get()), "");
649 TEST(ScopedPtrTest
, SelfResetAbortsWithDefaultArrayDeleter
) {
650 scoped_ptr
<int[]> y(new int[4]);
651 EXPECT_DEATH(y
.reset(y
.get()), "");
654 TEST(ScopedPtrTest
, SelfResetAbortsWithDefaultFreeDeleter
) {
655 scoped_ptr
<int, base::FreeDeleter
> z(static_cast<int*>(malloc(sizeof(int))));
656 EXPECT_DEATH(z
.reset(z
.get()), "");
659 // A custom deleter that doesn't opt out should still crash.
660 TEST(ScopedPtrTest
, SelfResetAbortsWithCustomDeleter
) {
661 struct CustomDeleter
{
662 inline void operator()(int* x
) { delete x
; }
664 scoped_ptr
<int, CustomDeleter
> x(new int);
665 EXPECT_DEATH(x
.reset(x
.get()), "");
669 TEST(ScopedPtrTest
, SelfResetWithCustomDeleterOptOut
) {
670 // A custom deleter should be able to opt out of self-reset abort behavior.
672 typedef void AllowSelfReset
;
673 inline void operator()(int*) {}
675 scoped_ptr
<int> owner(new int);
676 scoped_ptr
<int, NoOpDeleter
> x(owner
.get());