
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