Boost logo

Boost :

From: Raoul Gough (RaoulGough_at_[hidden])
Date: 2002-04-04 15:54:54


> From: "Peter Dimov" <pdimov_at_[hidden]>
> To: <boost_at_[hidden]>
> Subject: Re: [boost] Re: boost::weak_ptr suggestions
> Date: Wed, 3 Apr 2002 21:30:53 +0300
> Organization: Multi Media Ltd.
> Reply-To: boost_at_[hidden]
>
> From: "Raoul Gough" <RaoulGough_at_[hidden]>
> > > From: "Peter Dimov" <pdimov_at_[hidden]>
> > > Right again. However, the primary methods of accessing a weak_ptr are
> (1)
> > > constructing a shared_ptr (which does throw) and (2) make_shared.
get()
> > has
> > > been retained for efficiency but is not recommended (in multithreaded
> > > programs.)
> >
> > So why the difference in error semantics between the single and
> > multi-threaded idioms? For example, if I converted single-threaded code
> that
> > uses get() to thread-safe code using make_shared, I also get changed
> > semantics for the invalid pointer case.
>
> Changed semantics? Why? Both get() and make_shared() return a NULL
pointer.

My apologies - I was assuming that make_shared would also throw. I can't
find make_shared in my copy of boost (1_27_0), but from the name I would
have thought that it would construct and return a shared_ptr (like
std::make_pair). Hence my assumption that it would incorporate the semantics
of the shared_ptr constructor.

In any case, it sounds like there is already a choice of error handling for
idiomatic weak_ptr access from multi-threaded code. I happen to write more
single-threaded code, so I still like the idea of an alternative throwing
get. I just can't think of a catchy name to distinguish it from the
non-throwing version - getvalid? getcond?

>
> > Incidentally, it looks like the use_count member function can determine
> > indirectly whether the target still exists or not. It seems a bit
obscure
> > though, seeing as the reference count is really an implementation detail
> and
> > distinct from the concept of null/valid/invalid.
>
> Correct, that's why I added weak_ptr::expired().

I like this - it looks like a good name for it, too.

>
> > BTW, am I right in thinking that sharede_ptr always maintains an extra
> weak
> > reference counter? I mean, even if my code doesn't use weak_ptr,
> shared_ptr
> > still has to maintain the extra counter, right? That, combined with the
> new
> > thread-safety features seems to cost something like a 10% performance
hit
> in
> > my smart pointer benchmark code (which sorts indexes to objects
containing
> > two strings each). That's on the total sorting time, not pointer access
> > time.
>
> Yes, you are right. It does make a difference in benchmarks.
>
> > It seems like boost is deliberately trying to avoid extra template
> > parameters for things like policies or allocators. OTOH, it seems a bit
> > unfair for code to pay for features which it doesn't require (e.g.
thread
> > safety or weak_ptr support). Has the option of adding an additional
policy
> > parameter to the shared_ptr template already been discussed?
>
> Numerous times. Usually people don't agree on the meaning of the
additional
> policy parameter. :-)
>
> Keeping shared_ptr non-parameterized has an important benefit: its type
> doesn't change. I can define my library interface in terms of
shared_ptr<T>
> and it will happily interoperate with every other shared_ptr<>-using
> library. Once you add that policy parameter, library A that chooses policy
X
> will no longer talk to library B that chooses policy Y, and using both
> libraries becomes problematic.

I can see that this would be a problem in some cases.

BTW, I'm still not 100% convinced about the shared_ptr/weak_ptr
combination - it means that users of boost::weak_ptr *must* use
boost::shared_ptr to manage the lifetimes of their objects. Given the
probable problem domain (data structures with cycles) I guess this would
never cause a real problem, but it's hard to be sure. I've been using my own
weak_ptr for a while now, which relies on explicit support from the target
objects. This has its own problems, but it means the target objects can be
allocated and managed in any way at all.

>
> This doesn't mean, of course, that we don't need a parameterized smart
> pointer. Only that (a) shared_ptr is not it, and (b) shared_ptr plus an
> additional policy parameter is not it.

Well, I don't know - presumably a more parameterized smart pointer would (at
least with some parameter combinations) duplicate the functionality of
shared_ptr, which would then make shared_ptr redundant.

An alternative would be to parameterize shared_ptr and provide the necessary
conversions between compatible types. For example, a thread-safe shared_ptr
probably holds identical data to a thread-unsafe one, so conversion from one
to the other (and back again) is trivial. There is already support for some
compatabililty with std::auto_ptr, which is even more different.

Regards,
Raoul Gough.

_________________________________________________________
Do You Yahoo!?
Get your free @yahoo.com address at http://mail.yahoo.com


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