|
Boost : |
From: David B. Held (dheld_at_[hidden])
Date: 2002-05-01 11:37:52
"Peter Dimov" <pdimov_at_[hidden]> wrote in message
news:00fd01c1f0fc$ade1dd50$1d00a8c0_at_pdimov2...
> [...]
> What I believe Greg means is that, if you have a library function:
>
> shared_ptr<T> create();
>
> you can change the way the T is allocated without breaking any client
code;
Ok, thanks for clarifying. That makes sense.
[Greg]
> > > I don't see why a policy-based smart pointer template cannot
> > > preserve this feature of shared_ptr.
[Peter]
> It is, except for the (pointer, deleter) constructor. The question is,
what
> does this prove? That you can rename shared_ptr<T> to Loki::SmartPtr<T,
> BoostRefCounted>?
Yes, that, which, in itself, has some merit; but more importantly, it proves
that a policy-based smart pointer *can* preserve the "run-time policy
selection" features of shared_ptr.
> The purpose of shared_ptr is:
>
> * to solve the "polymorphic objects in containers" problem;
> * to provide a smart pointer that works with incomplete types - helps for
> pimples;
Good, and a template policy-based smart pointer (TPSP) can do these
as well.
> * to provide a standard smart pointer that (a) is the agreed-upon
> "transport" for library interoperability, and (b) can be used as a
> "firewall" between a library and a client, insulating the client from
> library changes (often in tandem with an abstract class.)
> * to "just work" in a variety in situations.
>
> The fact that someone can write an ownership policy for it is irrelevant.
Not at all. A TPSP can be made to behave just like shared_ptr. That
can even be made the *default* behaviour. And in that emulation, it
can enjoy all the benefits of shared_ptr that you list above, *including*
library interoperability and library/client insulation. That is, it could
simply be agreed that the default configuration of Loki::SmartPtr is *the*
standard way to pass pointers between libraries and clients.
What the TPSP gives you that shared_ptr does not, is the ability to
configure pointers with different semantics and performance character-
istics. It saves common implementation code to avoid redundancy.
Consider shared_ptr + weak_ptr + intrusive_ptr. First, they share a
fair amount of code. Simply be "renaming" them to
SmartPtr<RefCounted>, SmartPtr<WeakRefCounted>, and
SmartPtr<IntrusiveCount>, you eliminate a good deal of the redundancy.
Second, because they are completely unrelated types, they must declare
each other friends in order to write conversion c'tors between them.
Such variations in SmartPtr need no friendship, because they are distinct
but related types. In fact, it is this distinct-but-related relationship
that
causes me to prefer SmartPtr<name-it-like-boost::*_ptr> over the
constellation of boost::*_ptr types. SmartPtr already defines conversions
between most of the sensible policy choices. Adding some more policies
and defining new conversions is simple, and doesn't require you to touch
unrelated policies. Adding conversions among boost::*_ptr types
requires you to touch several different classes.
Don't get me wrong. I think the shared_ptr interface is very important.
So important, that a TPSP should probably emulate it out of the box.
And yes, it has some cool ideas, like the custom deleter that lets you
keep pointers to all kinds of things that lesser pointers couldn't handle
properly. But the fact that many of the implementation details are fixed
is a limiting factor. If we can preserve the interface and semantics, but
allow for more imlementation variations, while *decreeing* that one
particular configuration is *the* "Universal Smart Pointer", why shouldn't
we pursue that? After all, writing conversions to the standard
configuration
in many cases is not even necessary (since they already exist), and writing
your own isn't difficult either. Is there something else I'm missing?
Dave
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk