Boost logo

Boost :

From: Mark Borgerding (mborgerding_at_[hidden])
Date: 2000-03-18 10:01:31


Greg Colvin wrote:

> > Some time ago, somebody raised the issue about implicit casts. And I
> > liked the idea very much. But since then the conversation died out and
> > nothing happened.
> >
> > The idea was that the implicit casts like:
> >
> > operator T*() const throw() { return ptr; }
> >
> > be replaced with:
> >
> > operator void*() const throw() { return ptr; }
> >
> > The reason is that such a pointer can be checked for NULLness, can be
> > assigned to other void*'s, but cannot be dereferenced by accident. In
> > addition, it will make all our smart pointers nicer, because the
> > BOOST_SMART_PTR_CONVERSION define will be a non-issue any more.
> >
> > I have not heard any strong voices against this, so unless somebody has
> > a good argument against, I would like to propose this change to all our
> > smart pointers.
>
> The impasse is that some users of smart pointers, myself
> included, actually want operator T*(). If you have generic
> code written to accept pointers then operator void*() won't
> do, and neither will get().
>

The biggest argument I have against operator T* is a situation like this:

You are on a big project with some resource leaks. The decision is made to
use smart pointers wherever possible.
Good!
So you go on a treasure hunt looking for "new"s in the code. In the
conversion process, many functions in the project are changed from something
like
    Beer * GetMeABeer()
to
    shared_ptr<Beer> GetMeABeer()

Still good. Right? Maybe. Maybe not.
    If the conversion operator Beer* is allowed, then any code that calls
GetMeABeer will still compile fine, even though it is assigning the result
into a Beer*. The runtime behavior of GetMeABeer will be to return a
shared_ptr<Beer> which , in turn, converts to Beer* on assignment. Then the
shared_ptr<Beer> goes away -- poof! ... deleting the Beer* as it goes. The
raw Beer* is left dangling because shared_ptr<Beer> was too quick to convert
to a Beer*.

Having a operator T* is convenient, but IMO, that convenience is
misleading. I think the slight unwieldiness of using get() is a small price
to pay for fewer runtime errors. If I have to choose between compile-time
checks and ease of use, I will choose the compile-time checks nearly every
time.

- Mark


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