
Thank you for another good suggestion Jarrad. This could certainly be done and would get around the problems with some other workarounds but it now forces all developers of factories to construct the shared_ptrs with special deleters. Granted this is really just a slight inconvenience but I'm also dealing with lots of legacy. This is certainly a viable work around but I'd still like to see a way that the shared_ptr implementation itself could handle this situation better. J.D. On Thu, Nov 20, 2008 at 6:47 AM, Jarrad Waterloo <jwaterloo@dynamicquest.com
wrote:
When the shared_ptr is constructed pass in a custom deleter which will among other things increment and decrement the library reference count by calling LoadLibrary[Ex] and FreeLibrary. Note using GetModuleHandleEx might be better than load library for incrementing reference count as the library has already been loaded less needs to be done.
-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of J.D. Herron Sent: Wednesday, November 19, 2008 5:38 PM To: boost@lists.boost.org Subject: [boost] Severe shared_ptr limitation WRT dynamically loadedlibraries
Hello, I would like to raise what I think is a serious limitation of the boost shared_ptr implementation. I have thought a bit about solutions but don't have anything concrete to offer as yet but would be interested in seeing the thoughts of the boost library developers. I work in an architecture that uses dynamically loaded factory patterns quite a lot and factories can also be dynamically unloaded. This also makes heavy use of shared_ptrs to make memory management a breeze. The basic problem is that the boost implementation of the sp_counted_base relies on virtual functions to deallocate which are implemented by various templates in the detail namespace. If I have a dynamically loaded factory interface that returns a shared_ptr, the factory implementation causes the templates to generate the virtual function code within the factory library. Everything is fine as long as the library stays loaded but if the library is unloaded, any client code holding the shared pointer to an object generated by that factory now has an invalid virtual function table for the sp_counted_base it holds. So when the reference count goes to zero an access violation is generated. It is stated that the shared_ptr is to be as close to a raw pointer as possible which I very much agree with. However this behavior really sets it apart from raw pointers as it is certainly possible for a factory to return a dynamically allocated raw pointer to client code, unload the factory library and have the client code deallocate the raw pointer after the unload with no problem.
To illustrate the problem in a windows environment, here is a simple example. Lets say 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 in this post, releasing the shared_ptr causes // an access violation spInt.reset() // THIS CRASHES! }
I would like to see a solution that would make this simple example and very reasonable use case work for shared_ptrs. Note that the argument that the client code cannot know what the factory is actually returning requires that the factory library be in memory so that appropriate subclass destructors can be called does not hold water here. This example uses simple integers. The root of the issue is not one of the virtual function table for the wrapped type getting corruped on library unload but rather the virtual function table for a member of the shared_ptr itself. I will put some thought toward this but am interested to see what boost developers might be able to come up with as well.
J.D. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost