【问题标题】:Linking errors while exporting std::vector from dll从 dll 导出 std::vector 时出现链接错误
【发布时间】:2015-11-19 10:06:38
【问题描述】:

我有一个使用 __declspec(dllexport) 导出结构的 dll (my_library.dll)。由于该结构包含std::vector<std::wstring> member,因此我还为它导出了函数,如下所示:

template class __declspec(dllexport) std::allocator<std::wstring>;
template class __declspec(dllexport) std::vector<std::wstring>;

请注意,我已经定义了宏,这样 dll 在编译时会在结构和向量之上导出并被导入(当 dll 被另一个应用程序使用时,通过 __declspec(dllimport))。 上面的 dll 构建良好。

现在这个 my_library.dll(和相应的my_library.lib)链接到一个exe(my_exe.exe)。这个 exe 有一个 .cpp 文件 (exe_source.cpp),它定义了一个 global std::vector&lt;std::wstring&gt; 变量。这个源文件编译得很好。 但是,在构建这个 exe 时,我收到以下错误:

my_library.lib(my_library.dll) : 错误 LNK2005: "public: __thiscall std::vector,class std::allocator

,类std::allocator,类std::allocator

::~vector,类 std::allocator ,类std::allocator,类std::allocator (void)" (??1?$vector@V?$basic_string@GU?$char_traits@G@std@@V?$allocator@G@2@@std@@V?$allocator@V?$basic_string@ GU?$char_traits@G@std@@V?$allocator@G@2@@std@@@2@@std@@QAE@XZ) 已经在 exe_source.obj 中定义

我怀疑 my_library.dll 定义和导出了所有std::vector&lt;std::wstring&gt; 函数,并且在exe_source.cpp 中使用全局std::vector&lt;std::wstring&gt; 变量也会导致定义许多std::vector&lt;std::wstring&gt; 函数,从而导致链接器抱怨发现此类函数的多个定义。

我是否正确理解了错误?

以及如何解决这个问题?

感谢您的宝贵时间。

【问题讨论】:

  • 即使你得到这个链接,导出你真的无法控制其内部实现的 C++ 类也不是一个好主意。如果您的应用使用不同的编译器选项、不同的编译器版本等进行编译,那么vector 与 DLL 使用的vector 将不同。
  • @PaulMcKenzie,感谢您的建议。但是,我认为可以正确导入向量,正如微软文章support.microsoft.com/en-us/kb/168958所建议的那样。
  • 无论它是否正确,这都不是一个好主意或习惯。正如@MrC64 的回答所说,这是一个非常脆弱的设计选择。
  • 你为未来积攒了大量的麻烦。忽略您所获得的建议,后果自负。
  • 我想澄清一下,我鼓励 OP 遵循更好的设计选择(正如我的回答中已经写的那样),例如让 DLL 导出 纯 C 接口(C++ 是内部 DLL的实现)。

标签: c++ stl linker dllimport dllexport


【解决方案1】:

首先,在 DLL 接口处具有 STL 类是一种高度约束的设计选择:事实上,必须构建 DLL 和使用它的其他模块(例如,由您的 DLL 客户端构建的 EXE)使用 same C++ 编译器版本并链接到 CRT DLL 的 same 风格。

更好的设计选择是导出具有纯 C 接口的 DLL(实现可以使用 C++,但您应该扁平化公共 API 以使其成为 C),或按照this CodeProject article 中的建议,使用类COM 方法导出C++ 抽象接口

假设您知道这一点,您应该能够删除这些行:

template class __declspec(dllexport) std::allocator<std::wstring>;
template class __declspec(dllexport) std::vector<std::wstring>;

只需导出托管您的 STL 数据成员的结构,例如:

MyLib.h

#pragma once

#ifndef MYLIB_API
#define MYLIB_API __declspec(dllimport)
#endif

#include <string>
#include <vector>

struct MYLIB_API MyLib_Data
{
    std::vector<std::wstring> Strings;
    // ... other stuff ...
};

MyLib.cpp

#define MYLIB_API __declspec(dllexport)
#include "MyLib.h"

// ... Implementation code ...

请注意,您可能会收到警告 C4251,类似于:

'MyLib_Data::Strings' : class 'std::vector<std::wstring,std::allocator<_Ty>>'
needs to have dll-interface to be used by clients of struct 'MyLib_Data'

但你可以忽略它。

【讨论】:

  • 但是我可以在 my_exe.exe 中使用向量吗?虽然我没有改变它,但我确实在 my_exe.exe 中使用了这个向量。 更新:不使用模板类语句会导致无法解决的外部错误,我在 exe 中迭代向量成员。
  • 假设您的 exe 是使用相同的 VC++ 编译器版本构建的,并且使用相同风格的 CRT 链接,是的。试试看吧。
  • 你一定是做错了什么:我用上面的代码 sn-p 和一个 EXE 尝试了一个简单的复制,通过基于范围的 for 遍历向量,字符串显示正确。 (当然,请确保将您的 EXE 与链接器生成并关联到您的 DLL 的 .lib 文件链接。)
  • 我在结构中有一个getter函数成员返回这个向量,我在exe中使用它并将它分配给一个局部向量变量并使用迭代器来迭代向量。
  • @AarCee:刚刚尝试添加一个简单的 getter,它也可以正常工作。
猜你喜欢
  • 1970-01-01
  • 2011-11-16
  • 2012-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-25
相关资源
最近更新 更多