
I have a suggestion for the shared pointer implementation to overcome a severe limitation it has currently regarding dynamically unloaded libraries. I posted a little while back regarding this problem which is illustrated with the following example from a Microsoft Windows environment. I have a simple factory interface like so: class Factory { public: virtual shared_ptr<int> GetIntSharedPtr() = 0; virtual int * GetIntRawPtr() = 0; }; I implement a factory DLL to provide one of these factories that has an exported function GetFactory() like so: /// implementation of the Factory interface class TestFactory : public Factory { public: virtual shared_ptr<int> GetIntSharedPtr() { return shared_ptr<int>( new int(5) ); } virtual int * GetIntRawPtr() { return new int(0); } }; /// Library instance of the factory implementation TestFactory g_Factory; /// Exported function to return the factory for this library _declspec(dllexport) extern "C" Factory & GetFactory() { return g_Factory; } This is compiled into a library named "TestFactory.dll". Now I create a simple command line application that does the following: /// Typedefinition for for the GetFactory exported function typedef Factory & (_cdecl * GetFactory)(); int main() { // dynamically load the TestFactory library HMODULE hFactoryDll = ::LoadLibrary( "TestFactory.dll" ); // get the GetFactory() interface from the loaded library GetFactory pfnGetFactory = ::GetProcAddress( hFactoryDll, "GetFactory" ); // Acquire the factory object Factory & factory = pfnGetFactory(); // Call the factory interfaces to get dynamically allocated integers int * pRawInt = factory.GetIntRawPtr(); shared_ptr<int> spInt = factory.GetIntSharedPtr(); // everything is fine so far, now unload the factory library ::FreeLibrary( hFactoryDll ); // deallocating the raw pointer recieved from the factory works just fine delete pRawInt; // THIS WORKS! // However due to the reasons outlined below, releasing the shared_ptr causes // an access violation spInt.reset() // THIS CRASHES! } The basic problem is that the shared_ptr implementation uses virtual functions in the sp_counted_base class that gets generated in the factory dll since it is a template instantiation and once that factory dll is unloaded the virtual function tables for all shared_ptrs it generated are now garbage. In my opinion the virtual function implementation in the template is an unnecessary design flaw that creates this limitation. I also think the reference counter just simply does too much. I would propose an alternative design that eliminated the use of virtual functions in template generated base classes and let the outer smart pointer class handle the deallocation chores and make the reference counter just a simple reference counter. This could eliminate the limitation illustrated in this simple and very common use case. Ignoring a bunch of stuff right now like custom deallocators, weak references, some basic members like assignment, etc., here is a simple reference counted smart pointer that is able to handle this library unloading example without a problem just as you could do with a raw pointer: /// reference counter THAT ONLY REFERENCE COUNTS AND HAS NO VTABLE class SimpleRefCounter { public: /// Constructor initializes reference count to 0 SimpleRefCounter( long count = 0 ) : m_Count(count) {} /// Increments the reference count and returns it long Increment() { return ::InterlockedIncrement( &m_Count ); } /// Decrements the reference count and returns it long Decrement() { return ::InterlockedDecrement( &m_Count ); } /// Returns the current reference count long Count() const { return m_Count; } private: long m_Count; }; /// Simple smart pointer template that handles the deallocation chores and therefor /// can be used safely across dynamic dll boundaries template < typename _type > class SmarterPtr { public: /// Default constructor creates a null pointer SmarterPtr() : m_pValue( NULL ), m_pRefCounter( NULL ) {} /// Constructor taking an allocated value to manage SmarterPtr( _type * p_pValue ) : m_pValue( p_pValue ) { m_pRefCounter = new SimpleRefCounter( 1 ); } /// Copy constructor SmarterPtr( const SmarterPtr & p_Original ) : m_pValue( p_Original.m_pValue ), m_pRefCounter( p_Original.m_pRefCounter ) { m_pRefCounter->Increment(); } /// Destructor releases ~SmarterPtr() { reset(); } /// Resets the managed pointer to the passed in one releasing the /// currently managed pointer and deallocating if necessary void reset( _type * pNewValue = NULL ) { if ( pNewValue != m_pValue ) { if ( m_pValue && 0 == m_pRefCounter->Decrement() ) { // need to deallocate current value delete m_pValue; delete m_pRefCounter; // ignore weak ref for now m_pValue = NULL; m_pRefCounter = NULL; } if ( pNewValue ) { m_pRefCounter = new SimpleRefCounter( 1 ); m_pValue = pNewValue; } } } private: _type * m_pValue; SimpleRefCounter * m_pRefCounter; }; Again the key is no VTABLE and deallocation handled by the exposed templates. Why shouldn't shared_ptr move to an equivalent model so it can be used across dynamic dll boundaries safely? J.D.