Virus721
Virus721

Reputation: 8335

weak_ptr - Dereferencing - Throw if expired

Dereferencing a weak_ptr does not automatically check whether the pointer has expired. Why is it designed this way ?

I would like to safely dereference weak pointers without first having to check them using expired() and throw an exception if they are null.

Would this be a good practice and what would be a right way to do that ? Should I overload * and -> operators so that they perform this check first ? Should I write a free function ?

Something like :

template< typename T >
weak_ptr< T > & check( weak_ptr< T > & p )
{
    if( p.expired() )
        throw logic_error( "Trying to dereference a null pointer." );
    return p;
}

And then :

weak_ptr< int > pi;
int i = *check( pi );

Thank you.

Upvotes: 4

Views: 4745

Answers (1)

rodrigo
rodrigo

Reputation: 98486

Using expired() is not useful because it will introduce races in multi-threaded programs. Also an exception is not nice, because having a weak_ptr expired is not so exceptional: they are designed precisely for that.

The nice trick around weak_ptr is that they are not dereferenceable. Instead, to access the object you call lock() that atomically returns a shared_ptr that points to the object, or to null if not available.

The normal way to access a weak pointer is:

void safe_do(weak_ptr<T> &w)
{
    shared_ptr<T> p = w.lock();
    if (p)
        p->do();
}

If you really want the exception, you can use this variant:

void safe_do2(weak_ptr<T> &w)
{
    shared_ptr<T>(w)->do(); //throws a bad_weak_ptr if w expired
}

Upvotes: 12

Related Questions