How to check if a weak_ptr is empty?

A

Alan Johnson

It seems useful to be able to distinguish between an empty weak_ptr and
one that has merely expired. For example:

void f(weak_ptr<T> wp)
{
if (/* wp is empty */)
{
// Act is if a NULL pointer was passed.
}
else
{
// Obtain a shared_ptr. Throw an exception if wp has expired.
shared_ptr<T> sp(wp) ;
}
}

There seems to be no way, however, to test a weak_ptr for emptiness. Is
this an oversight in the design, or a deliberate design decision?
 
P

Phlip

Alan said:
It seems useful to be able to distinguish between an empty weak_ptr and
one that has merely expired. For example:

Note that A> Boost questions will work best on the Boost mailing list, and
that B> you could pass a pointer to a NullObject and take out the if, and C>
you should typedef all template instances, including private ones like
weak_ptr<T>.

That said...
void f(weak_ptr<T> wp)
{
if (/* wp is empty */)

if (wp.get() == NULL) ? If not, then:

if (wp.operator->() == NULL)
There seems to be no way, however, to test a weak_ptr for emptiness. Is
this an oversight in the design, or a deliberate design decision?

And if the design intends to prevent this test, then maybe my suggestions
won't work, for some obscure reason.

Posting to the Boost mailing list will decrease the odds that posts like
mine will get reviewed and possibly corrected.
 
P

Pete Becker

Alan said:
It seems useful to be able to distinguish between an empty weak_ptr and
one that has merely expired. For example:

void f(weak_ptr<T> wp)
{
if (/* wp is empty */)
{
// Act is if a NULL pointer was passed.
}
else
{
// Obtain a shared_ptr. Throw an exception if wp has expired.
shared_ptr<T> sp(wp) ;
}
}

This code doesn't illustrate why this distinction is useful. A more
idiomatic way to write it would be:

shared_ptr<T> sp(wp);
if (!sp)
// Act as if a null pointer was passed

Constructing a shared_ptr object from a weak_ptr object is not an
expensive operation. I don't see any good reason to try to avoid it.

But if for some reason you don't want to do that, you can check
wp.use_count() == 0.
 
P

Pete Becker

Phlip said:
Note that A> Boost questions will work best on the Boost mailing list, and

On the other hand, questions about TR1 and about standard C++ work best
here. shared_ptr and weak_ptr are in TR1 and, as of last month, in the
next version of the C++ standard.
 
A

Alan Johnson

Pete said:
This code doesn't illustrate why this distinction is useful. A more
idiomatic way to write it would be:

shared_ptr<T> sp(wp);
if (!sp)
// Act as if a null pointer was passed

Consider the non-smart-pointer version of a function:

void f(T *p)
{
if (p)
{
// Case 1: Do one thing.
// Case 2: Undefined behavior because p isn't valid.
}
else
{
// Case 3: Do another thing.
}
}

The obvious solution to avoiding Case 2 above is to simply not pass an
invalid pointer. But that isn't always easy. Consider this motivating
example. You have a server that allows multiple users to connect.
While connected, they may schedule events to occur at some time in the
future. Your "event" objects store a pointer to the user that scheduled
them. What should you do, though, if a user schedules an event to be
processed 30 minutes from now, and then immediately disconnects?

A lot of solutions come to mind, but a particularly simple one is to
have your events store a weak_ptr to the scheduling user, and then find
out about invalid users in Case 2. (Yes, in this contrived example you
could distinguish Case 2 from Case 3 prior to calling f, but that isn't
the point.)

The question is how to distinguish "a weak_ptr to nothing" (Case 3) from
"a weak_ptr to something invalid" (Case 2).

Constructing a shared_ptr won't work. Consider the following fragment,
in which BOTH constructions of a shared pointer will throw bad_weak_ptr.

weak_ptr<T> wp1, wp2, wp3 ;

{
shared_ptr<T> temp_sp(new T) ;
wp1 = temp_sp ;
wp2 = temp_sp ;

// Case 1: wp1 is a valid weak_ptr
share_ptr<T> sp1(wp1) ;
}

// Case 2: wp2 is an invalid weak_ptr
shared_ptr<T> sp2(wp2) ;

// Case 3: wp3 is a valid weak_ptr, but pointing to nothing.
shared_ptr<T> sp3(wp3) ;


The use_count() member is equally problematic, as it returns 0 for both
an invalid weak_ptr and a weak_ptr to nothing. Likewise, lock() will
return an empty shared_ptr in both cases. The only way I've found that
does seem to work is something like:

bool is_empty(weak_ptr<T> wp)
{
weak_ptr<T> empty ;

// operator < claims to establish a strict weak order, so this
// should always work.
return (!(wp < empty) && !(empty < wp)) ;
}


It is my opinion that throwing bad_weak_ptr when constructing a
shared_ptr from an empty weak_ptr is a design flaw. The "proper" thing
to do would be to construct an empty shared_ptr.
 
A

Alan Johnson

Alan said:
It is my opinion that throwing bad_weak_ptr when constructing a
shared_ptr from an empty weak_ptr is a design flaw. The "proper" thing
to do would be to construct an empty shared_ptr.

Actually, to be technical, I think this is a symptom of the problem.
The latest tr1 smart pointer proposal I can find is:
<url: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html>

It says that shared_ptr's weak_ptr constructor throws bad_weak_ptr when
the weak_ptr has expired, which is as it should be.

It also says that weak_ptr's expired() returns "use_count() == 0". This
is the problem. If the weak_ptr is empty, expired() should ALWAYS
return false. It is impossible for an pointer to nothing to expire.

With that change, the "more idiomatic way" that you suggest would work
as expected.
 
P

Phlip

On the other hand, questions about TR1 and about standard C++ work best
here. shared_ptr and weak_ptr are in TR1 and, as of last month, in the
next version of the C++ standard.

Were my other answers the best possible?
 
P

Pete Becker

Phlip said:
Were my other answers the best possible?

I'm not familiar with Boost's version of shared_ptr and weak_ptr. In TR1
and the standard, weak_ptr doesn't have member functions get() and
operator->(), so you can't use them to figure out whether a weak_ptr
object is empty. The only information you can get directly from a
weak_ptr object is its use count and whether it's expired. For anything
else, you have to copy it into a shared_ptr object.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top