【问题标题】:Use auto_ptr in VC6 dll cause crash在 VC6 dll 中使用 auto_ptr 导致崩溃
【发布时间】:2010-04-16 02:24:51
【问题描述】:
// dll
#include <memory>

__declspec(dllexport) std::auto_ptr<int> get();

__declspec(dllexport) std::auto_ptr<int> get()
{
    return std::auto_ptr<int>(new int());
}

// exe
#include <iostream>
#include <memory>

__declspec(dllimport) std::auto_ptr<int> get();

int main() {
    {
        std::auto_ptr<int> x = get();
    }
    std::cout << "done\n";
    getchar();
}

下面的代码在VC9下运行完美。但是,在 VC6 下,我会立即遇到崩溃并显示以下消息。

调试断言失败!

程序: C:\Projects\use_dynamic_link\Debug\use_dynamic_link.exe 文件:dbgheap.c 行:1044

表达式: _CrtIsValidHeapPointer(pUserData)

VC6下是不是不能导出auto_ptr?

通过DLL导出STL集合类是一个已知问题。

Access Violation When Accessing an STL Object Through A Pointer or Reference In A Different DLL or EXE

但是,我搜索了一下,没有看到任何关于 std::auto_ptr 的信息。

有什么解决方法吗?

【问题讨论】:

    标签: c++ visual-c++


    【解决方案1】:

    DLL 有自己的堆,因此您必须确保从同一上下文中新建和删除。

    【讨论】:

    • 为什么VC9没有出现这个问题?
    • 好的。我确实找出了为什么在 VC9 中不会出现问题。在 VC9 中,我动态链接到运行时库。在 VC6 中,我使用的是静态链接。请参阅我发布的其他答案。
    【解决方案2】:

    我的第一个猜测是 VC9 中的 exe 和 dll 项目设置为 CRT 作为共享 dll 的目标,而 VC6 项目中的一个或两个目标是静态 CRT(非 dll)。

    另外,dll 和 exe 都针对共享 CRT dll 的不同版本(因此它们实际上使用 2 个不同的 CRT)。

    在 VC6 中,选中 C/C++ 项目属性的代码生成类别中的运行时库选项。确保 exe 和 dll 都针对相同的 DLL 库选项。

    【讨论】:

      【解决方案3】:

      您违反了 ODR(一个定义规则),并且成员函数很可能是内联的 - 因为它们内联了 std::auto_ptr 的两个不同定义,所以您会得到未定义的行为。

      最重要的是,正如 Eddy 指出的那样,当auto_ptr::~auto_ptr 释放持有的对象时,它将在 EXE 中调用 operator delete,而不是在调用 operator new 的 DLL 中。这种不匹配也会导致崩溃。

      一般来说,导出实现的类是非常脆弱的(接口类仅由纯虚函数组成,并导出一个免费的工厂函数用于构造)是可以的,然后你不要在类上使用__declspec(dllexport),只在工厂函数。

      【讨论】:

      • 看起来像鸡蛋和鸡肉的问题。由于异常安全,我的自然反应是在 dll 函数返回的指针周围放置一个 auto_ptr。但后来我可能会遇到不同运行时问题的删除问题。
      • @user:尝试com_ptr_t,并在对象本身中实现Release 函数。 COM/DCOM/ActiveX 使用这种方法在模块/编译器/语言/运行时之间共享组件效果很好。
      【解决方案4】:

      好的。我意识到根本原因。这是由

      引起的

      DLL 内存管理器混淆

      DLL memory manager mixup

      1. 从 DLL 分配内存

      2. 返回指向EXE的指针

      3. 尝试从EXE中删除指针

      如果我们动态链接到运行时库(在选项 C/C++ -> 代码生成 -> 使用运行时库下),步骤 (3) 只会正常工作

      如果我们静态链接到运行时库,DLL使用的内存管理器可能与EXE使用的内存管理器不同。

      【讨论】:

      • 您的意思是项目设置中的运行时库选项混淆了?
      猜你喜欢
      • 1970-01-01
      • 2016-04-23
      • 1970-01-01
      • 1970-01-01
      • 2011-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多