我的DLL加载了LoadLibrary
- 它们是否仍然可以共享运行时,还是我必须确保在分配的同一个DLL中删除对象?
在我的示例中,我有一个在DLL模块中实现的公共基类,然后由Lua对象镜像,Lua确定其生命周期。因此,当Lua垃圾收集器决定这样做时,我需要释放该对象,并且我无法预测将从哪个DLL中进行垃圾收集。
我在考虑每个DLL都有以下函数的副本:
int ReleaseObject(lua_State* L)
{
// object pointer is stored in field [0]
lua_rawgeti(L, -1, 0);
delete (Object*) lua_touserdata(L, -1);
return 0;
}
然后,指向此函数的指针将放在metatable __gc
字段中,metatable将用于该DLL中定义的派生类的所有实例。这足以保证安全删除吗?
答案 0 :(得分:1)
考虑在dll的客户端上使用std::unique_ptr
或std::shared_ptr
(使用自定义删除器调用ReleaseObject),这些可以正确处理跨dll边界删除。
同样,保持dll接口完全extern "C"
是一个很好的做法,这样dll就可以使用不同的c ++运行时进行编译,并且名称保持不变。
不是从dll继承基类实现,而是导出BaseImpl* CreateBaseImpl();
void DeleteBaseImpl(BaseImpl*);
更好
这对函数让它们返回一个指向你需要的实现的指针。然后该指针应该被送到您选择的智能指针。使BaseImpl的公共接口只使用原始类型(句柄,数字,指向这样的指针,C数组 - 好; stl容器 - 不好:创建cpp运行时依赖)
我想它可能看起来像:
// code using LUA - unconcerned with the cross-dll nature of the implementation
...
{
auto p = new ConcreteImpl(); // pass p to LUA as you normally would
...
// when LUA wants it deleted:
delete p;
p = nullptr;
// probably tell LUA it was deleted
}
...
// BaseImpl.h - Dll Interface header
class BaseImpl;
extern "C" BaseImpl * CreateBaseImpl();
extern "C" void DeleteBaseImpl(BaseImpl *p);
// Client code
#include "BaseImpl.h"
#include <type_traits>
#include <memory>
#include <Windows.h>
class ConcreteImpl { // no inheritance probably necessary
{
using namespace std;
...
ConcreteImpl()
: m_ptrDll( ::LoadLibraryW(L"BaseImpl.dll"), &::FreeLibrary )
, m_ptrBase( nullptr, [](BaseImpl *){} )
{
Assert( m_ptrDll, "LoadLibraryW() failed err=0x%x", ::GetLastError() );
auto pfnCreate = reinterpret_cast<decltype(&CreateBaseImpl)>(
::GetProcAddress(m_ptrDll.get(), "CreateBaseImpl") );
auto pfnDelete = reinterpret_cast<decltype(&DeleteBaseImpl)>(
::GetProcAddress(m_ptrDll.get(), "DeleteBaseImpl") );
Assert( pfnCreate && pfnDelete,
"GetProcAddress() failed err=0x%x", ::GetLastError() );
// use move constructor to assign new value
m_ptrBase = decltype(m_ptrBase)( pfnCreate(), pfnDelete );
Assert( m_ptrBase, "CreateBaseImpl returned nullptr" );
}
...
// methods that use m_ptrBase go here
...
unique_ptr<
remove_pointer<HMODULE>::type,
decltype(&::Freelibrary)
> m_ptrDll;
unique_ptr<BaseImpl, decltype(&DeleteBaseImpl)> m_ptrBase;
};