Hi again, thx for all your replies.
Quote:Original post by ToohrVyk
Antheus' suggestion interacts badly with multiple inheritance. However, there's a lot of truth in what he says: give your class a pointer to the stored object and a pointer to a shared reference count integer. This is equivalent to adding a a global reference field with another level of indirection to your RefCountData object.
If I understood you correctly, you suggest adding T* as a member to each RefCountPtr<T> instance. This way it's possible to un-template RefCountData which is shared.
A very simple solution. I got it working below. I still need a reinterpret_cast, but I guess it's safe if there's no vtable involved.
Right now this will get me going. I think i'll have to look into boost::shared_ptr later on to find out how they did it; adding a ptr-member to each RefCountPtr instance seems like redundant data.
First the Non-Working example:
#include <iostream>template< typename T > class RefCountPtr{ template< typename T > class RefCountData; // Private Inner Class Forward Declaration template< typename U > friend class RefCountPtr; // Enable Access To RefCountData* Of Other RefCountPtr Typespublic: RefCountPtr( T* ptr ) : m_pRefCountData( new RefCountData< T >( ptr ) ) { m_pRefCountData->AddCount(); } RefCountPtr( const RefCountPtr< T >& in ) : m_pRefCountData( in.m_pRefCountData ) { m_pRefCountData->AddCount(); } template< typename U > RefCountPtr( const RefCountPtr< U >& in ) { // Getting Rid Of The const... RefCountPtr< U > constHack( in ); // Evil Cast m_pRefCountData = reinterpret_cast< RefCountData< T >* >( constHack.m_pRefCountData ); m_pRefCountData->AddCount(); } ~RefCountPtr() { m_pRefCountData->RemoveCount(); } T* operator->() const { return m_pRefCountData->GetPtr(); } T& operator*() const { return *( m_pRefCountData->GetPtr() ); }private: RefCountData< T >* m_pRefCountData;private: template< typename T > class RefCountData { public: RefCountData( T* ptr ) : m_Ptr( ptr ), m_nCount( 0 ) { } void AddCount() { ++m_nCount; }; void RemoveCount() { if( --m_nCount == 0 ) { delete m_Ptr; delete this; // "delete this" Works If The DTor Is Empty // And If "this" Won't Be Accessed Afterwards } }; T* GetPtr() { return m_Ptr; }; private: T* m_Ptr; unsigned int m_nCount; };};struct Base1{ virtual ~Base1() {}; virtual void Test1() = 0;};struct Base2{ virtual ~Base2() {}; virtual void Test2() = 0;};struct Derived : public Base1, public Base2{ Derived() : Base1(), Base2() {}; virtual ~Derived() {}; virtual void Test1() { std::cout << "Test1\n";}; virtual void Test2() { std::cout << "Test2\n";};};int main( int, char** ){ // Ok RefCountPtr< Derived > pDerived( new Derived() ); pDerived->Test1(); pDerived->Test2(); // Ok RefCountPtr< Base1 > pBase1( pDerived ); pBase1->Test1(); // Error, Calls Test1() !! RefCountPtr< Base2 > pBase2( pDerived ); pBase2->Test2(); // Output: // // Test1 // Test2 // Test1 // Test1 return 0;}
Now the Working example:
- RefCountData now only holds the counter, no template needed.
- each RefCountPointer holds a copy of the pointer to the encapsulated object
#include <iostream>template< typename T > class RefCountPtr{ class RefCountData; // Private Inner Class Forward Declaration template< typename U > friend class RefCountPtr; // Enable Access To RefCountData* Of Other RefCountPtr Typespublic: RefCountPtr( T* ptr ) : m_pRefCountData( new RefCountData() ), m_Ptr( ptr ) { m_pRefCountData->AddCount(); } RefCountPtr( const RefCountPtr< T >& in ) : m_pRefCountData( in.m_pRefCountData ), m_Ptr( in.m_Ptr ) { m_pRefCountData->AddCount(); } template< typename U > RefCountPtr( const RefCountPtr< U >& in ) { // Getting Rid Of The const... RefCountPtr< U > constHack( in ); // Evil Cast, but i guess it's safe now m_pRefCountData = reinterpret_cast< RefCountPtr< T >::RefCountData* >( constHack.m_pRefCountData ); m_Ptr = in.m_Ptr; m_pRefCountData->AddCount(); } ~RefCountPtr() { if( m_pRefCountData->RemoveCount() == 0 ) { delete m_pRefCountData; delete m_Ptr; } } T* operator->() const { return m_Ptr; } T& operator*() const { return *( m_Ptr ); }private: T* m_Ptr; RefCountData* m_pRefCountData;private: class RefCountData { public: RefCountData() : m_nCount( 0 ) { } unsigned int AddCount() { return ++m_nCount; }; unsigned int RemoveCount() { return --m_nCount; }; private: unsigned int m_nCount; };};struct Base1{ virtual ~Base1() {}; virtual void Test1() = 0;};struct Base2{ virtual ~Base2() {}; virtual void Test2() = 0;};struct Derived : public Base1, public Base2{ Derived() : Base1(), Base2() {}; virtual ~Derived() {}; virtual void Test1() { std::cout << "Test1\n";}; virtual void Test2() { std::cout << "Test2\n";};};int main( int, char** ){ // Ok RefCountPtr< Derived > pDerived( new Derived() ); pDerived->Test1(); pDerived->Test2(); // Ok RefCountPtr< Base1 > pBase1( pDerived ); pBase1->Test1(); // Ok!! :D RefCountPtr< Base2 > pBase2( pDerived ); pBase2->Test2(); // Output: // // Test1 // Test2 // Test1 // Test2 return 0;}