c++ - 释放 DLL 创建的对象

标签 c++ dll lua

我的 DLL 是用 LoadLibrary 加载的 - 它们是否仍然可以共享运行时,或者我实际上是否必须确保对象在分配它们的同一个 DLL 中被删除?

在我的示例中,我有一个在 DLL 模块中实现的公共(public)基类,然后由 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;
}

然后指向此函数的指针将被放置在元表 __gc 字段中,元表将用于该 DLL 中定义的派生类的所有实例。这足以保证安全删除吗?

最佳答案

考虑在 dll 的客户端上使用 std::unique_ptrstd::shared_ptr(带有调用 ReleaseObject 的自定义删除器),它们可以处理正确地跨 dll 边界删除。

此外,将您的 dll 接口(interface)完全保留 extern "C" 也是一个好习惯,这样 dll 就可以使用不同的 c++ 运行时进行编译,并且名称不会混淆。 与其从 dll 继承基类实现,不如导出一个 BaseImpl* CreateBaseImpl(); void DeleteBaseImpl(BaseImpl*); 一对函数,让它们返回一个指向您需要的实现的指针。然后应该将该指针馈送到您选择的智能指针。使 BaseImpl 的公共(public)接口(interface)仅使用原始类型(句柄、数字、指向此类的指针、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;        
};

关于c++ - 释放 DLL 创建的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20236461/

相关文章:

c++ - C2664 错误 C++ Visual Studio

.net - x-64 计算机上的 Oracle.DataAccess.Dll 加载问题

sockets - lua 套接字 POST

multithreading - 如何检测和快速完成响应时间太长的lua功能?

c++ - 使用 C++ 在二叉搜索树中存储值

c++ - 具有任意数量参数的模板函数

c++ - curl_slist_free_all() 在带有 Debian 8.7 的 GKE 上导致段错误

c++ - 在 MinGW 构建的项目中链接 MSVC 编译的 DLL

c# - 在 64 位进程中加载​​ 32 位 dll

makefile - Centos7如何安装lua5.3