Subject: Re: [boost] scoped_ptr deleter
From: Howard Hinnant (howard.hinnant_at_[hidden])
Date: 2009-09-16 11:47:29
I've been lurking on this thread for awhile now, and as a person who
is very familiar with the design and use of single-ownership smart
pointer with custom-deleter capability, I figured it was time to throw
my two cents in...
I find custom deleters handy with single-ownership even when I'm not
trying to move them out of scope. I usually use:
const unique_ptr<MyClass, MyDeleter<A>> p(...);
The const qualifier on the unique_ptr renders the unique_ptr to be
practically the same thing as scoped_ptr. It will take a const_cast
for this animal to transfer the ownership out of the scope.
I've also found that sometimes I'll start with a same-scope use, but
during refactoring, learn that I want to move the smart pointer
creation into a factory function (for reuse in several places). When
I do that, it is handy to not have to change smart pointer types
(besides dropping the const qualifier if I used that).
I've also found support for statefull deleters quite necessary (as
opposed to just handling stateless deleters). The proposed code:
class D = boost::checked_deleter<T> > // first patch line
deleter()(ptr); // second patch line, instead of
does not handle statefull deleters. If this community does decide to
put a custom deleter into scoped_ptr (and I am ambivalent on that
decision), then I strongly encourage the designers of this patch to
mimic the custom deleter of unique_ptr. The latest specification of
it can be found here:
(search for "[unique.ptr]")
And here is a more readable link in tutorial form which hits the
(and includes a C++03 emulation).
The basic layout would look like:
class D = boost::checked_deleter<T> > // checked_deleter<T> should
be partially specialized to handle arrays
typedef typename details::compute_pointer<T, D>::type pointer;
tuple<pointer, D> ptr_;
Until tuple is rewritten with the empty member optimization, you'll
want to use compressed_pair<pointer, D> instead.
The "compute_pointer" business defaults to T* unless D::pointer
exists, in which case pointer is D::pointer. This supports putting
this smart pointer in shared memory. Allocators, which are a common
use case, often have this nested type, and sometimes, it is not a raw
Storing the D as shown above will:
1. Optimize away the space for it when D is empty.
2. Support function pointer types.
3. Support non-empty (statefull) Ds.
I also recommend supporting lvalue-reference D types. This is very
handy when dealing with a stateful D that you don't want to move or
copy (say because it is a data member of the enclosing class). Such
support will probably come for free in C++0x, but requires a little
extra work in C++03 to avoid the reference-to-reference situation.
I also recommend deleter accessors which return *references* to the
const D& get_deleter() const;
It is not uncommon to need access to the actual stored deleter (not a
copy of it) during the lifetime of the smart pointer (I needed this
just yesterday in code I was writing). This is used to change the
state of the deleter which alters the behavior the deallocation
process (e.g. do (or don't) destruct a certain field in the held
And you'll want scoped_ptr constructors which accept a deleter (to
initialize its state). And you'll want to disable the constructors
which don't take a deleter when D is a pointer or reference type (lest
it be null).
scoped_ptr<A> could be a nice synonym for scoped_array<A> if
checked_deleter is specialized for T. It is nothing more (or less)
than a nice, easy to remember name for the array variant of the smart
When you get done, you will have reinvented all of the const parts of
unique_ptr (which has several years of refinement under its belt by
now). I don't necessarily discourage that as it is a very educational