From: Kevlin Henney (Kevlin.Henney_at_[hidden])
Date: 1999-07-18 05:06:45
> 1. Exception behaviour occurs only for sharing, not for acquisition
That is a true statement, but does not explain an advantage.
Yes, I was just listing the properties, as opposed to b/w
> 2. The object that is being acquired is not jettisoned at the first
> of trouble.
This characterization is frought with bias. It condemns with its tone
without explaining why there is a problem with the current behavior (if any
The characterisation of the characterisation is perhaps a little strong,
but I'll offer a couple of examples where this is beneficial below.
Please note that the current behavior of the constructor is similar to
passing ownership of the object with an auto_ptr. Ownership is assumed by
the constructor immediately upon its invocation.
This is the same for all of the smart pointers in question.
> 3. The functions that could throw exceptions are clearly defined.
I don't see how that's any different from the current situation.
Again, this is a property that is worth stating as it means that the
different models are balanced in this respect. If /3/ were not true,
there would be no debate ;-)
> In both cases there are the same number of operations that could
> but they are different in each case, ie acquisition in the first model
> and sharing in the second. The second model is non-lossy wrt the body
Describing the first model as "lossy" again condemns without explaining any
disadvantage. Is it your intention that the shared_ptr should take (shared)
ownership of the body object? If so, the body will certainly be deallocated
when the last shared_ptr is destroyed. In what sense is that less "lossy"
than in the existing model?
When the object has been in use and the last reference goes, then it
goes -- this is, after all, the whole point. The distinction here is
that with the current model, the object may never get the opportunity to
be used, and therefore will be lost soon after creation, regardless of
the cost of that creation or the significance of the object. The model I
am discussing means that the object will always be usable through a
shared_ptr, and will never be lost because of failure on the part of the
shared_ptr. In other words, when I hand over custody of an object, I can
be sure that the custodian will /1/ take ownership, and /2/ will not
fail to do so, thus taking the object in custody down w/ it.
> The second model also offers an allocation optimisation for
> certain uses. In terms of recovery actions, the way I see it, the
> model requires less in the way of recovery.
(Many good implementations of exception handling will incur no runtime cost
for these recovery actions.)
Usually you want a shared_ptr because you want to optimize copying. There's
already a presumably large overhead at initialization time because of the
dynamic allocation and construction of the body. Please give a concrete
example where it would be useful to optimize for initial construction of
handle at the expense of copying.
Not quite: usually you want to use a shared_ptr because you wish to have
explicit shared semantics. If you wish to optimise copying, ie using
hidden reference counts and copy-on-write, this is a different model,
and a difference that is not often acknowledged.
In terms of cost, the second allocation is deferred until the object is
shared. This may never actually take place, so there is an effect on the
semantics wrt guarantees, as well as a minor redistribution -- and
potential saving -- of overhead.
A couple of examples that spring to mind that would be better off w/
failure on sharing rather than on acquisition:
/1/ Static initialisation in a dynamically loaded library:
shared_ptr<T> p(new T(...)); // or acquisition from a factory
A failure to initialise p would lead to terminate, even though the
resource was correctly allocated.
/2/ An object pooling facility (connections, threads, etc) which had
custody of a number of many objects, each of which might be costly to
create or have particular significance wrt their identity. To enable
sharing out of resources it makes sense if the shared_ptr mechanism is
used. If the resources can be initialised, it is expected that the
pool would initialise successfully. This suggests the alternative
model. If a resource is never shared out, this has the benefit that it
(marginally) reduces the overhead required to manage it (ie the count
never rises above 1, and no count object is ever allocated).
> The issue worth
> discussing arises from the ctor fix tagged "fix: prevent leak if new
> throws", when it is not altogether clear that this will _always_ be a
> leak given the user's requirements and calling context.
No, it would only be a leak in the most natural and obvious case of
initializing the shared_ptr.
"the most natural and obvious case" is hardly rigorous. I am merely
calling into question a hidden assumption that is easy to miss, and will
be cleared up when the example section is instantiated. It is perhaps
easy for us to forget -- as we have worked very closely w/ the code and
concepts involved for some time -- that for newcomers to any library,
such assumptions are not necessarily obvious.
> and if shared_ptr adopts the second
> set of semantics it becomes a closer and more subsitutable relative of
This is the first time you've hinted at a real advantage to your suggested
semantics. I buy that argument, but I don't think it outweighs the
disadvantages, in particular that copying can throw.
Indeed, there is no such thing as a free lunch, and one model has a
different set of trade offs to the other.
eGroups.com home: http://www.egroups.com/group/boost
http://www.egroups.com - Simplifying group communications
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk