第一个问题的答案:调用 dll 中的虚拟析构函数 - 有关其位置的信息嵌入在您的对象中(在 vtable 中)。在内存释放的情况下,这取决于您的用户的纪律性IBase
。如果他们知道他们必须调用Release()
并认为异常可以以令人惊讶的方向绕过控制流,那么将使用正确的。
但是如果CreateInterface()
返回shared_ptr<IBase>
它可以将正确的释放函数绑定到这个智能指针。您的库可能如下所示:
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
因此,您的 DLL 的每个用户都可以轻松防止资源泄漏。他们永远不必费心调用Release()
或关注异常绕过他们的控制流。
要回答您的第二个问题:其他答案清楚地说明了这种方法的缺点:您的听众必须使用与您相同的编译器、链接器、设置、库。如果它们可能很多,这可能是您图书馆的主要缺点。您必须选择:安全与更大的受众
但是有一个可能的漏洞:在你的应用程序中使用shared_ptr<IBase>
,即
{
shared_ptr<IBase> p(CreateInterface(), DestroyFromLibrary);
...
func();
...
}
因此,没有实现特定的对象通过 DLL 边界。然而,您的指针安全地隐藏在 之后,即使 是否抛出异常shared_ptr
,谁也会在正确的时间调用。DestroyFromLibrary
func()