2

我遇到了奇怪的崩溃。我正在尝试将我的应用程序的各种模块(基于 MFC,在 VS2005 中开发)分离成 DLL。以下是我试图实现它的骨架代码:

在一个常见的头文件中(比如 base.h):

class Base {
    vector<message> messages;
    ...
    ...
};

在 DLL 源代码的头文件中(比如 class.h):

class Derived : public Base {
private:
    int hoo();
    ...
public:
    void foo();
    int goo();
    ...
};

extern "C" __declspec (dllexport) Derived* CreateDerived();

在类.cpp

 Derived* CreateDerived()
 {
    return new Derived;
 }

在主应用程序代码的文件中:

#include "base.h"
#include "class.h"

typedef Derived* (*DerivedCreator)();
...
...

void LoadDll()
{
    //DLL Load Code...
    ...
    ...

    DerivedCreator creator = reinterpret_cast<DerivedCreator>(::GetProcAddress(dllHandle, "CreateDerived"));

    Derived* pDerived = creator();

    pDerived->messages.push_back(message("xyz"));//Crashes here...
}

问题是当我尝试访问 Base 类的向量成员时,代码会出现问题。这仅在发布模式下发生。它在调试模式下工作正常。当我在发布模式下从 Visual Studio 执行它时收到的错误消息是:

“Microsoft Visual Studio C 运行时库在三星 SSD Magician.exe 中检测到一个致命错误。

按 Break 调试程序或按 Continue 终止程序。”

但是当我直接执行发布二进制文件并将调试器附加到它时,我得到了访问冲突。此时,如果我在调试器中检查向量,它会在其中显示 6 位条目,它们都不可读。我能够在派生指针中看到基类其余成员的正确值。

任何帮助将非常感激。

4

1 回答 1

2

跨 DLL 边界传递 stl 容器是很危险的。这里的原因是每个模块(主应用程序和 DLL)都有自己的堆实例。如果您在 DLL 的上下文中分配动态内存,然后将指针传递给应用程序并在应用程序的上下文中释放该内存,这会导致堆损坏。

这正是您的示例中发生的情况。

Derived* pDerived = creator();

CreateDerived叫做。

 Derived* CreateDerived()
 {
    return new Derived;
 }

new Derived在 DLL 堆中分配内存。

pDerived->messages.push_back(message("xyz"));

在 内部push_back,为 分配了额外的内存Base::messages,并且该分配是在应用程序堆上完成的。碰撞!

一个结论是,您需要重新考虑 DLL 接口,以便仅在 DLL 内部对向量执行所有操作。

于 2012-04-20T11:22:28.210 回答