c++ - 删除在 DLL 中创建的对象

标签 c++ dll

删除在 DLL 中创建的对象时,我需要一些有关运行时/堆问题的说明。在我提出问题之前需要一些介绍...

在我的项目中,一个 DLL(由其名称指定)返回一个新的 Grabber 对象。在我的代码的早期版本中,DLL 导出了如下函数:

extern "C"
__declspec(dllexport) Grabber* CreateGrabber(string settings)
{
    return new SomeSpecificGrabber(settings);
}

在 EXE 中,我使用了这样一个静态函数来创建一个新的 Grabber 对象:

static Grabber* createGrabberObject(const std::string& grabberType, const std::string& grabberSettings)
{
    FARPROC hProc = 0;

    // load dll with the name of grabberType
    HMODULE hDLL = LoadLibrary(grabberType.c_str());

    // get address for CreateGrabber function
    hProc = GetProcAddress(hDLL, "CreateGrabber");

    // instantiate a function pointer of our type and typecast the address
    // of the CreateGrabber function to this type
    CreateGrabberFunctionType CreateGrabberFunction = (CreateGrabberFunctionType)hProc;

    // call CreateGrabber in DLL to get a Grabber object
    return CreateGrabberFunction(grabberSettings);
}

在 EXE 中,Grabber 对象的生命周期由智能指针管理:

shared_ptr<Grabber> myGrabberObj = shared_ptr<Grabber>(createGrabberObject("SomeGrabber.DLL", "Settings"));

只要我使用 /MDd 设置 (VC++ 2010) 编译 EXE 和 DLL,这一切都可以正常工作,这意味着 EXE 和 DLL 使用相同的堆。

现在我想用 /MTd 设置编译我的解决方案。有了这个,我为传递给 DLL 的设置字符串对象获得了 _CrtIsValidHeapPointer 类型的运行时断言。这是有道理的,因为 DLL 试图删除在 EXE 中创建的字符串对象。他们不再使用同一个堆。

我通过稍微更改导出的 DLL 函数(const char* 而不是 string)解决了这个问题:

extern "C"
__declspec(dllexport) Grabber* CreateGrabber(const char* settings)
{
    return new SomeSpecificGrabber(settings);
}

createGrabberObject 中,我将 grabberSettings.c_str() 而不是 grabberSettings 传递给 DLL 函数。

现在一切正常了。但现在是我的第一个问题:为什么当myGrabberObj 被删除时我没有得到_CrtIsValidHeapPointer 断言?该对象是从 DLL 中创建的,但从 EXE 中删除(通过智能指针)。为什么我这里没有遇到与上面的字符串对象相同的问题?

我想一个干净的解决方案是 DLL 也导出这样的函数:

extern "C"
__declspec(dllexport) void DeleteGrabber(Grabber* grabber)
{
    delete grabber;
}

然后我的 EXE 中也会有一个静态函数,它在 DLL 中调用 DeleteGrabber:

static void deleteGrabberObject(const std::string& grabberType, Grabber* grabber)
{
    FARPROC hProc = 0;

    // load dll with the name of grabberType
    HMODULE hDLL = LoadLibrary(grabberType.c_str());

    // get address for DeleteGrabber function
    hProc = GetProcAddress(hDLL, "DeleteGrabber");

    // instantiate a function pointer of our type and typecast the address
    // of the DeleteGrabber function to this type
    DeleteGrabberFunctionType DeleteGrabberFunction = (DeleteGrabberFunctionType)hProc;

    // call DeleteGrabber in DLL
    DeleteGrabberFunction(grabber);
}

然后这个静态函数可以被智能指针自动调用:

shared_ptr<Grabber> myGrabberObj = shared_ptr<Grabber>(createGrabberObject("SomeGrabber.DLL", "Settings"), 
boost::bind(deleteGrabberObject, "SomeGrabber.DLL", _1));

这也行。但我的第二个问题来了:静态函数createGrabberObjectdeleteGrabberObject 都加载了DLL。这是否意味着因为加载了两个 DLL 实例而创建了两个不同的堆(那么这个解决方案根本无法解决我的问题)?或者这两个静态函数是否使用相同的堆?

我希望有人能解释这里发生了什么......

最佳答案

DLL 是引用计数的,不会加载两次,当您使用 LoadLibrary 时,它只会加载一次,并且它们将使用相同的堆。静态函数是解决这个问题的正常方法。

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

相关文章:

c++ - 为什么下面的线程安全栈实现没有死锁?

c++ - 为另一个 dll 导出静态成员

c# - 将 C 字符串返回到 C# 程序

dll - 如何将 TeamCity 构建版本获取到非托管 DLL 和 OCX 控件中?

c++ - 如何在 C 语言中通过按键退出 while 循环?

c++ - 使用 boost::is_any_of 的多个拆分 token

c++ - 语义略有不同的复制构造函数和赋值运算符中是否存在陷阱?

c# - 调用 C dll 函数来更改 C# 中传递的参数

delphi - 如何在Delphi XE2上调试2个dll?

C++ 编译器对齐 - 仅字符无填充