The answer to your first question: A virtual destructor is called in your DLL - information about its location is built into your object (in the vtable). In the case of freeing up memory, it depends on how disciplined your IBase users IBase . If they know that they should call Release() and consider that the exception can bypass the control flow in an amazing direction, the right one will be used.
But if CreateInterface() returns shared_ptr<IBase> , it can bind the correct release function to this smart pointer. Your library might look like this:
Destroy(IBase* p) { ... // whatever is needed to delete your object in the right way } boost::shared_ptr<IBase> CreateInterface() { IBase *p = new MyConcreteBase(...); ... return shared_ptr<IBase>(p, Destroy); // bind Destroy() to the shared_ptr } // which is called instead of a plain // delete
Thus, each user of your DLL is easily prevented from leaking resources. They never have to worry about calling Release() or pay attention to exceptions that bypass unexpectedly bypass the control flow.
To answer the second question: The disadvantage of this approach is clearly expressed by the other answer s: your audience should use the same compiler, linker, settings, libraries as you. And if they can be quite a lot, this can be a serious flaw for your library. You must choose: security against a wider audience
But there is a possible loophole: Use shared_ptr<IBase> in your application, i.e.
{ shared_ptr<IBase> p(CreateInterface(), DestroyFromLibrary); ... func(); ... }
Thus, no specific implementation object is passed across the DLL boundary. However, your pointer is safely hiding behind shared_ptr , which calls DestroyFromLibrary at the right time, even if func() throws an exception or not.
phlipsy Oct 22 '09 at 8:43 2009-10-22 08:43
source share