Boost logo

Boost :

From: Michael Grundberg (michaelgrundberg_at_[hidden])
Date: 2003-10-24 01:16:13


"Peter Dimov" <pdimov_at_[hidden]> wrote:
> A very common use for associatives of shared_ptr is to track objects.
> You just create set< shared_ptr<void> > or map< shared_ptr<void>, Data

> > and use a shared_ptr<X> as a key to find the associated information;
> note that this works regardless of X.
>

I haven't used shared_ptrs in that way, but I can certainly see the
benefits.

> In a typical scenario, both operator< implementations behave
> identically. The differences arise when an object has several
> addresses (usually with multiple inheritance, but not always) or, as
> in your case, several associated counts.
>
> Neither implementation is inherently more correct, but if the default
> operator< compared values, you'd have no way of getting the current
> behavior, while you can easily write a value-comparing predicate
> yourself.

Although one could also argue that the current operator < should be
converted into a predicate, leaving the operator < to compare against
addresses :)

> You should also consider shared_ptr's relationship with weak_ptr.
> weak_ptr's operator< can't compare values, since a weak_ptr can expire

> anytime, and then there would be no value to compare (accessing the
> value of a deleted pointer is undefined behavior in addition to being
> unsafe ;-)). You can't just use 0 as the value since operator< must be

> stable or the std::set's invariant will break as its elements start to

> expire.
>
> For this reason, weak_ptr's operator< compares count pointers, and
> there is an additional reason - consistency - for shared_ptr's
> operator< to match this behavior.
>

Ah, didn't think of this. I knew there was something I must have missed!

> I see three ways to deal with the problem, one hi-tech and two
> low-tech. :-)
>
> Hi-tech:
>
> Use something like the following function to create the shared_ptr
> instances associated with a resource:
>
> template<class R, R * pr> shared_ptr<R> make_resource_pointer() {
> static shared_ptr<R> q(pr, null_deleter());
> return q;
> }
>

This was really cool! I will try this out.

> Low-tech 1:
>
> Add
>
> static shared_ptr<R> pi(&i, null_deleter());
>
> after every
>
> int i;
>
> resource and use pi consistently. Or even hide 'int i' someplace safe
> and only expose pi to people.
>
> Low-tech 2:
>
> Comment out shared_ptr's operator<, compile, add the necessary
> predicate to every std::set pointed to by the compile errors. :-)
>
> > Also, the definition of the less operator for shared_ptr causes
> > std::set::find and std::find to operate in different ways, since the

> > later uses the == operator instead of <. Was this the intent?
>
> Yes, this is intentional, if not especially elegant. :-)
>

Ok :)

Thanks alot for your explanation, it helped clearing the smoke! If not
exactly the answers I wanted to hear, they at least make me able to
explain to fellow colleagues what they must and mustn't do when using
shared_ptrs :)

/Michael


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