Boost logo

Boost :

From: Peter Dimov (pdimov_at_[hidden])
Date: 2002-08-28 09:01:33


From: "Douglas Gregor" <gregod_at_[hidden]>
> On Tuesday 27 August 2002 12:18 pm, Peter Dimov wrote:
> > If we really need the above to be supported, the right approach is:
> >
> > * mem_fn must recognize weak_ptr and either perform
> >
> > (shared_ptr<X>(x)->*&X::foo)();
>
> Or just let the precondition on mem_fn's operator() be:
> get_pointer(x) != 0

This is already the case.

> and rely on the get_pointer overload for weak_ptr. It's not much different
> than calling this illegal:
>
> mem_fn(&X::foo)(static_cast<X*>(0));

This is undefined behavior, whereas the above is defined.

> > or call X::foo only when x is nonzero, and silently do nothing otherwise
> > (but this is only applicable to void functions.)
>
> I'd shy away from this type of behavior, because it could get quite
confusing,
> especially because the result of mem_fn is generally passed to template
> functions...

Yes, it could. There are two perfectly legitimate behaviors for
bind(&X::foo, wp), depending on the context. Case 1 is when this is a nested
bind in a complicated function object, and the proper behavior is to throw
an exception when the weak pointer has been invalidated. Case 2 is

vector< weak_ptr<X> > v;

for_each(v.begin(), v.end(), mem_fn(&X::f));

and the proper behavior here is almost always to only call X::f for live
objects and ignore the rest.

This is one of the reasons why mem_fn does not currently work with weak_ptr
arguments, requiring the user to explicitly select the appropriate behavior
for the given context.

> > (I'm undecided whether this coupling is a good thing, and I'm not sure
> > whether lack of partial ordering on some compilers may prove a problem.)
>
> I wouldn't be overly concerned with partial ordering; it seems that
problem
> can be solved in a portable way with a few tricks. The easy solution
> (get_pointer for weak_ptr) doesn't add any coupling that isn't already
there.

This is not "an easy solution" because it doesn't solve anything, and it
creates additional problems that weren't present before.

We can waste some more time if you like, but it's easier just to accept the
fact that get_pointer is not part of weak_ptr's interface. From this
conversation I get the impression that get() should never have been, too.

> > * The signal must recognize weak_ptr too; a weak_ptr tracks the object
> > lifetime regardless of whether the object is-a trackable.
>
> Right. The difference being that you have to 'poll' a weak_ptr to
determine if
> it is still connected or not.

Actually no, you don't have to poll the weak_ptr. Polling the weak_ptr is as
incorrect as is allowing bind(&X::f, wp). You can poll the weak_ptr, see
that it's valid, call &X::f, and end up with the weak pointer invalidated,
either by a different thread, or (indirectly) by X::f itself.

You have to either "lock" the weak pointer by creating a shared_ptr
temporarily out of it, or (much easier) catch the use_count_is_zero
exception and disconnect. I don't know how this affects your combiner
infrastructure, though; it might be difficult to arrange.

What does the signal currently do when a slot throws an exception?

> I'm fine with holding off the changes for this release. weak_ptr support
in
> Signals does us no good if weak_ptrs can't be used by bind/mem_fn anyway.

Of course they can. It's just that the user needs to explicitly select the
behavior.

template<class T> struct weak_to_shared
{
    typedef shared_ptr<T> result_type;

    shared_ptr<T> operator()(weak_ptr<T> const & p) const
    {
        return shared_ptr<T>(p); // throws on dead reference
    }
};

signal.connect(bind(&X::f, bind(weak_to_shared<X>(), wp)));

The weak_ptr "problem" aside, why do you need to track scoped_ptr,
shared_ptr and intrusive_ptr?


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