|
Boost : |
From: Andrei Alexandrescu (andrewalex_at_[hidden])
Date: 2003-01-28 02:29:25
"Beman Dawes" <bdawes_at_[hidden]> wrote in message
news:4.3.2.7.2.20030127213406.022872f8_at_mailhost.esva.net...
> At 05:47 PM 1/27/2003, Andrei Alexandrescu wrote:
>
> >Q. Why doesn't shared_ptr provide (your pet feature here)?
> >A. Because (your pet feature here) would mandate a reference counted
> >implementation or a linked list implementation, or some other specific
> >implementation. This is not the intent.
> >
> >This is a presupposition. Someone wants to mandate lazy
> >initialization/specific dereference testing/specific initialization
> >testing/tons others. Would any of these require a refcounted/reflinked
> >implementation?
>
> That particular FAQ item was written quite a while ago, before weak_ptr
> support, before custom deleter support, etc. We had gotten several
requests
> for features that seemed to tilt the spec strongly toward one or the other
> of the implementation techniques.
>
> The question of whether "any of these require a refcounted/reflinked
> implementation?" is a good one.
>
> The question came up with use_count(), and was handled by not requiring
> use_count() be constant complexity.
>
> For a shared-ownership smart pointer with weak_ptr support, I expect some
> people will say that mandates a refcounted rather than reflinked
> implementation. I don't think that is true, but it may make a reflinked
> implementation less attractive. What's your opinion on that?
Thanks for asking! It just turns out that when writing mc++d I racked my
brains for a long while on whether, and when, reference linking (RL) is
better than reference counting (RC) and couldn't find a good argument. The
thing I like most about RL is that it never fails (is strongly exception
safe). RC can fail during creation if creating a new counter fails. For
many, this is just an academic argument, but for me it does carry some
weight. A little weight, though :o).
So in the end I did decide to include reference linking as a sample
ownership policy, partly as a proof of the soundness of the Ownership policy
interface. It's just a couple dozen lines, and if someone needs it, they can
use it. I myself never felt the need though.
While we're at it: use_count() should return an unsigned type.
On a related subject: I did consider writing about the shared global map
approach, but I considered (and still consider) it too non-scalable and with
too many issues. Guess some very particular applications might use something
like that, but frankly I doubt the concept applies broadly enough to warrant
even mentioning in a standards document.
Here are some more debatable comment that I'd like to add, at the cost of
getting mortified :o).
> That particular FAQ item was written quite a while ago, before weak_ptr
> support, before custom deleter support, etc. We had gotten several
requests
> for features that seemed to tilt the spec strongly toward one or the other
> of the implementation techniques.
It should be noted that the constructor taking a custom deleter has many
implementation efficiency consequences that are not mentioned in the
Standards proposal nor in the shared_ptr doc. My feeling is that the
documentation at
http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1397.html and at
http://www.boost.org/libs/smart_ptr/shared_ptr.htm is coy about mentioning
that the added constructor requires quite some more overhead under the
covers, including runtime polymorpshim, virtual calls, extra allocations,
all those good things. Ah, there's also the compulsive locking on
multithreaded builds (whether the user wants it or not). These all make
shared_ptr impossible to implement as efficient as a handcoded one while
respecting the interface requirements.
In light of all that, I disagree with the statement "Among all the choices,
boost::shared_ptr stands out as best meeting the requirements for a Standard
Library smart pointer" and "The rationale for inclusion of shared_ptr in the
Standard Library is very strong." Not to mention that the latter should be
inferred from the document by the readers, as opposed to stated explicitly.
As an argument to committee's opinion that "A policy-based design is seen as
the only candidate likely to meet this criteria", the answer is "Please
study the shared_ptr two-argument constructor that allows a custom deleter."
Again, it's worth mentioning that there's much more going on about that
constructor than just it being a cool constructor.
There's also a contradiction in there. The document nicely continues "One of
the reasons shared_ptr has been so successful is that in the great majority
of cases it supplies all the features that users need." However, only two
paragraphs below, in response to committee's "Proliferation of Standard
Library smart pointers is a serious concern", we read the following:
"scoped_ptr, scoped_array, and shared_array have been removed from the
proposal."
Am I the only one who sees the fly in the ointment?
If shared_ptr is the factotum, how come there are some other pointers in
boost that needed to be removed from the proposal? Why was their
functionality deemed necessary? Also, what's the deal with weak_ptr? And
Sherlock Holmes would also like to ask, why are there new smart pointers
added to boost on a regular basis?
The committee also mentions that "LWG members are very concerned that "you
don't have to pay for what you don't use." To this, the answer is "Issues
related to weak_ptr are a side issue that can be resolved after the basic
proposal is accepted. Also, be aware that different implementation
techniques are possible, and they may make various speed vs space tradeoffs.
These choices are not mandated by the proposal."
I think much more detail is fair at this point. Why resolve an issue after
the proposal is accepted? What implementation techniques are possible, and
what tradeoffs do they make? IMHO, the interface proposed (notably the
custom deleter) does mandate quite some.
Andrei
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk