Boost logo

Boost :

From: Frank Mori Hess (fmhess_at_[hidden])
Date: 2008-05-03 13:33:43


On Saturday 03 May 2008 08:38, Peter Dimov wrote:
> > On Friday 02 May 2008 08:18, Peter Dimov wrote:
> > > What I had in mind is illustrated with the following:
> > >
> > > X * px = new X;
> > > // px->shared_from_this(); // throws bad_weak_ptr
> > > weak_ptr<X> wx = px->weak_from_this(); // OK
> > > assert( wx.use_count() == 0 ); // expired
> > > shared_ptr<X> sx( px );
> > > assert( wx.use_count() == 1 ); // shares ownership with sx
> >
> > It's not clear to me that this kind of behavior could be implemented
> > for weak_ptr without changing its specification.
>
> It's compatible with the specification of weak_ptr. use_count() returns
> the number of shared_ptr instances in the ownership group. Before the
> shared_ptr line, this number is zero, after it, it's one, exactly what
> is reported.

What I'm thinking is more along the lines of how a weak_ptr goes
from "expired" to "good". Currently, that can only happen by assignment
of a new shared_ptr. And assignment of one expired weak_ptr has no effect
on any copies of the weak_ptr, they stay expired. It seems to me you
would need to add a fourth weak_ptr state to the existing "empty", "good",
and "expired" states, let's call it "reserved". A "reserved" weak_ptr
would have a use_count of zero, but any copies of it would be related to
it in the sense that when a reserved weak_ptr is assigned a shared_ptr, it
and all its copies all move from the "reserved" state to the "good" state
together. And some kind of token would need to be added for use as a
parameter to a new constructor that creates a "reserved" weak_ptr.

> > Also, it doesn't allow for distinguishing between "object alive but
> > no shared_ptr owner yet" and "shared_ptr expired or object destructed"
> > cases.
>
> Yes, it doesn't.

If the idea of a "reserved" weak_ptr was added, it could be made to throw a
different exception than bad_weak_ptr (perhaps derived from bad_weak_ptr)
when an attempt is made to construct a shared_ptr from it.

> > For the use case of tracking signal/slot connections, the signal would
> > want to be able to distinguish between the two cases, temporarily
> > blocking the connection in the first, and disconnecting it permanently
> > in the second.
>
> In the first case, the signal should proceed to invoke the slots without
> the one that is in process of being constructed. I agree that it makes
> it hard to automatically disconnect the connection when its weak_ptr
> expires. In theory, you can avoid this by simply not disconnecting
> automatically.

Yes, but in the case of a long-lived signal with many short-lived
connections, it would effectively create a resource leak when relying on
automatic connection management.

> > What does seem to have the right semantics is for weak_from_this() to
> > return something like a shared_ptr<weak_ptr<T> >. Every call would
> > return a shared_ptr that points at the unique weak_ptr which will be
> > assigned the object's owning shared_ptr.
>
> It seems to me that now you have a data race on the weak_ptr target,
> which would require synchronization.

Yes, the shared_ptr<weak_ptr<T> > would have to be wrapped in a class with
a mutex to make it thread-safe, or weak_ptr itself would have to provide
stronger thread-safety guarantees. Also, it should really have a const in
there: shared_ptr<const weak_ptr<T> >.

-- 
Frank



Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk