Re: [c++0x] considerations regarding active issue #711 (contradiction in empty shared_ptr)
Rodolfo Lima ha scritto:
Peter Dimov spotted a contradiction in shared_ptr specification
regarding the notion of an empty shared_ptr, as can be seen in
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2612.html#711
He proposed two solutions, preferring the first one, where a
shared_ptr can be empty in the sense that it owns nothing, but have a
stored pointer (i.e, get() returns non-null).
My objection to this solution is that code that uses common smart
pointer patterns can behave in a way that's different when dealing
with a non-aliasing shared_ptr. For instance:
// non-aliasing shared_ptr
shared_ptr<int> sptr(new int(3));
weak_ptr<int> wptr;
if(sptr)
{
wptr = sptr;
assert(wptr.lock() == sptr); // since sptr is in scope, this
should be ok
}
// aliasing shared_ptr
shared_ptr<int> aux;
int i;
shared_ptr<int> sptr(aux, &i);
weak_ptr<int> wptr;
if(sptr)
{
wptr = sptr;
assert(wptr.lock() == sptr); // assertion failure!
}
The problem lies in the fact that in the aliasing shared_ptr example,
(bool)sptr == true and use_count()==0. Whoever, for some reason,
relies on the premise that whenever use_count()==0, (bool)sptr ==
false, will be surprised.
Well, I understand that in in the pre-alias bool(ptr) was equivalent to
use_count() == 0 || get() == nullptr, but in my mind it has always been
equivalent to get() == nullptr only, because use_count() == 0 always
implied get() == nullptr. With the alias wording, this implication is no
longer true. In option 1, Peter Dimov simply sanctions the common sense,
that is to make bool(ptr) equivalent to get() == nullptr. Now, I'm
terribly sorry that the previous code would break, but I am even more
sorry that in order to get the same behaviour with the current interface
you need to call use_count() which is deliberately described as a
non-efficient function. However, I'm sure that any shared_ptr
implementation might detect the "empty" case in an efficient way, just
as unique() might do. So I guess we should add a new observer empty()
for this task. The code above would become:
if(!sptr.empty())
{
wptr = sptr;
assert(wptr.lock() == sptr); // always ok
}
By using Dimov's second solution, IMHO the shared_ptr/weak_ptr will
have a more common (and expected) behavior, and as a plus the user
won't have to bother with using dangling pointers, as the following
code will always do the right thing:
if(sptr)
sptr->some_function();
I don't dislike this option, either. However, we would be missing the
empty/non-null case. The question is: is this case useful? is it worth
the added complexity of the interface? I'm starting to have a negative
feeling about it.
Just my opinion,
Ganesh
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]