Boost logo

Boost :

From: Gavin Collings (gcollings_at_[hidden])
Date: 2000-03-03 11:36:01


>
> void func( const smart_ptr<myClass>& pMyClass ) {
> if ( pMyClass != NULL ) {
> otherFunc( pMyClass );
> pMyClass->dereference(); // this line is dangerous
> }
> }
>
> In the dereference line, the pointer might be NULL since otherFunc()
> might have released it. So introducing release() would change semantics
> of all other methods. And this change does not seem to be for the
> better.
>
> If you found a way to retain the internal pointer, so the pointer is
> left in the smart_ptr but is now in the converted_to smart pointer as
> well, that is different. But that does not seem easy at all...
>
> Or, use of release can be restricted to only when refCount in the
> smart_ptr is 1. While you seem to imply this restriction, after little
> reflection, I am starting to believe that it any non trivial use of the
> smart_ptr it will be quite hard to guarantee a refCount of 1.
>

I think which ever way it is defined, release() would need to have warning
labels attached. As you point out, it's an unpleasant choice between
potentially dangling references and usability restrictions. And leaving the
internal pointer in the original seems to imply distributing detailed knowlege
of other pointers' ownership models - not nice. This is really what led me on
to think about using proxy classes as an alternative to partially enforce /
document the intended usage - and to provide a place to keep a pointer if it
needs to be re-instated.

I'm not sure I've got you example straight, but for the sake of argument, lets
assume we're dealing with shared_ptrs and assume otherFunc() above is currently
defined to take a shared_ptr<myClass> which it then passes on to some other
library routine beyond our control which takes an auto_ptr<myClass> as a
parameter - which then eats the contained pointer. Currently, it can't be done
using shared_ptr, with release() it can

   void otherFunc( shared_ptr<myClass> sp_myclass )
   {
      auto_ptr ap( sp_myclass.get() ); // no good - two owners
      auto_ptr ap( sp_myclass.release() ); // or.. maybe ok - as above

      lib_func( ap );
   }

IMO, if a programmer *needs* to call lib_func, not allowing a him to do so means
he's going to find some work around using raw pointers anyway, and is more
likely to be put off by the smart pointer approach. Better to let him take the
risk?
 
But, going on to the proxy class approach, otherFunc could declare itself as

   void otherFunc( shared_ptr_sink_proxy<myClass> spp_myclass )
   {
      auto_ptr ap( spp_myclass ); // conversion invoked
      lib_func( ap );
   }

The crucial difference being that the dangerous line above is now known to be
unsafe since it follows the call of a routine that says so.

I'm not convinced by the approach yet, but it does seem to have some merit.
Perhaps I should have a go at it, but I think I'd like a little more feedback
first.

Gavin.


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