Boost logo

Boost :

From: Miki Jovanovic (miki_at_[hidden])
Date: 2000-02-07 18:26:44


Hello all,

OK, first I have to appologise for my code being in my own style...
I have been working quite happily at work when an idea occured to
me on how to make the shared_ptr polymorphic. For whatever reason
I could not use the boost library, so I quickly jogged down this
version of a polymorphic smart pointer.

The problem I was trying to solve is: allow shared_ptr<DescendentClass>
to be used anywhere shared_ptr<ParentClass> is expected.

Below is the VERY VERY rough cut of the code. Basically I am just
bouncing the idea of you guys, to see if my approach has some merit.
The reason I rushed so, is that I cannot find anything wrong with it,
and frankly I cannot believe my idea is that good. Method has potential
to be backwardly compatible with shared_ptr, it is just as fast, and
provides all the functionality one needs from a polymorphic pointer.

So, before I invest days of my life making this into presentable form,
can you guys comment on the concept.

Cheers,

Miki Jovanovic.

// main.cpp

#ifndef NULL
#define NULL 0
#endif

/*
 * NonCopyable
 */
class NonCopyable {
   protected:
      NonCopyable() {} // so noone can create objects of this type
      ~NonCopyable() {} // so people don't delete objects by calling
this non-virtual destructor
   private:
      NonCopyable( const NonCopyable& ); // disable copy constructor
      operator=( const NonCopyable& ); // disable copy operator
};

/*
 * PtrBase
 */
template <typename T> class PtrBase : NonCopyable {
   public: // public interface
      template<typename D> PtrBase& cast( const PtrBase<D>& ptr ) {
         if ( _pRefCount != ptr._pRefCount ) {
            release();

            dynamicShare( ptr._pObject, ptr._pRefCount );
         }
         return *this;
      }

      void clear() {
         release();
         assign( NULL );
      }

   protected: // helper routines
      PtrBase() {}
      explicit PtrBase( T* pObject ) { assign( pObject ); }

      ~PtrBase() {
         release();
      }

      void assign( T* pObject ) {
         try {
            _pRefCount = new int(1);
         }
         catch ( ... ) {
            delete pObject;
            throw;
         }
         _pObject = pObject;
      }

      template<typename D> void share( D* pObject, int* pRefCount ) {
         _pObject = pObject;
         _pRefCount = pRefCount;
         (*_pRefCount)++;
      }

      template<typename D> void dynamicShare( D* pObject, int*
pRefCount ) {
         T *pCastObject = dynamic_cast<T*>( pObject );
         if ( pObject == NULL || pCastObject != NULL ) {
            _pObject = pCastObject;
            _pRefCount = _pRefCount;
            (*_pRefCount)++;
         }
         else {
            assign( NULL ); // dynamic_cast failed
         }
      }

      void release() {
         if ( _pRefCount != NULL && --(*_pRefCount) <= 0 ) {
            delete _pRefCount;
            delete _pObject;
         }
      }

   protected: // data
      T *_pObject;
      int *_pRefCount;
};

/*
 * Ptr
 */
template<typename T, class B = PtrBase<T> > class Ptr : public B {
   public:
      explicit Ptr( T* pObject = NULL ) : B( pObject ) {}
      Ptr( const Ptr& ptr ) { share( ptr._pObject, ptr._pRefCount ); }
      Ptr& operator=( const Ptr& ptr ) {
         if ( _pRefCount != ptr._pRefCount ) {
            release();

            share( ptr._pObject, ptr._pRefCount );
         }
         return *this;
      }

      T* ptr() const { return static_cast<T*>( _pObject ); }
      T* operator->() const { return ptr(); }
};

class X {
public:
   virtual ~X() {}
   virtual void method() {}
   void x() {}
};

class Y : public X {
public:
   virtual ~Y() {}
   virtual void method() {}
   void y() {}
};

class Z : public Y {
public:
   virtual ~Z() {}
   virtual void method() {}
   void z() {}
};

typedef Ptr<X> XPtr;
typedef Ptr<Y,XPtr> YPtr;
typedef Ptr<Z,YPtr> ZPtr;

/*
 * t
 */
void t( const XPtr& p ) {
   p->method();
}

/*
 * main
 */
int main( int, char** ) {
   XPtr x1( new X() );
   YPtr y1( new Y() );
   ZPtr z1( new Z() );

   XPtr x2( z1 );
   y1 = z1;
   z1.cast( x2 );

   X *pX = z1.ptr();
   Y *pY = z1.ptr();
   Z *pZ = z1.ptr();

   z1->z();
   y1->y();

   t( x1 );
   t( z1 );

   return 0;
}


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