Boost logo

Boost :

From: Peter Dimov (pdimov_at_[hidden])
Date: 2003-12-11 12:32:54


Rani Sharoni wrote:
> Peter Dimov wrote:
>> Rani Sharoni wrote:
>>> One question: why shared_count::shared_count(weak_count const &)
>>> throws boost::bad_weak_ptr and what can be done when catching such
>>> exceptions?
>>
>> The corresponding nothrow equivalent is weak_ptr::lock:
>>
>> if( shared_ptr<X> px = wp.lock() )
>> {
>> // do something with *px
>> }
>> else
>> {
>> // handle the wp.expired() case
>> }
>
> In many cases that I've encountered, this indicates about programming
> error but this can be easily refined using wrapper that asserts on
> the validity of the pointer.

I think I understand where you're coming from; a piece of code uses a raw
pointer to an object since it assumes that the object will not be deleted,
and the same code is changed to use weak_ptr instead?

In this case an expired weak_ptr is indeed a programming error and the else
branch should ring the alarm bell accordingly.

weak_ptr is not limited to such scenarios. It is often used as a poll-based
replacement for the event-based Observer pattern (the object notifies its
observers when it's destroyed.) In this case, expiration does not signal a
programming error, merely that the observed object has been destroyed:

if( shared_ptr<X> px = target.lock() )
{
    attack(*px);
}
else
{
    select_target();
}

>> The constructor should be used in situations where, well, an expired
>> weak_ptr should cause an exception. :-)
>
> My concern that it might become like Java cast that might fail yet I
> assume that many programmers doesn't realize that it changes their
> failure guarantee and therefore probably affect the correctness of their
> programmers. The power and weakness of implicit failure handling.

The correctness is not affected, actually; one form of undefined behavior is
replaced with another. ;-)

>>> It seems to have potential impact on the failure guaranty
>>> of many functions such as impl::getX (Obtaining a shared_ptr to
>>> this).
>>
>> In this case, bad_weak_ptr signals that the object is not managed by
>> a shared_ptr, i.e. a programming error.
>
> I'm surprised to see that you accept that programming error might
> trigger an exception especially since http://tinyurl.com/yrxs
> significantly affected my mind set about contact violations.

A programming error might trigger an exception, since an exception is a
"legal" manifestation of undefined behavior.

It is true that, depending on the contract of getX, assert or lock() may be
more appropriate than just using the constructor. But that's not really the
point of the illustrative example, it merely shows how
enable_shared_from_this can be emulated by the user, if necessary.

The TR1 specification of enable_shared_from_this is of course not required
to throw bad_weak_ptr, it resorts to the old trusty undefined behavior. ;-)
Now that you mention it though, perhaps we should change
boost::enable_shared_from_this from

    shared_ptr<T> shared_from_this()
    {
        shared_ptr<T> p(_internal_weak_this);
        BOOST_ASSERT(p.get() == this);
        return p;
    }

to

    shared_ptr<T> shared_from_this()
    {
        shared_ptr<T> p = _internal_weak_this.lock();
        BOOST_ASSERT(p.get() == this);
        return p;
    }

to make this clearer.


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