C++ 从DLL导出STL std::basic_字符串模板时,出现LNK2005错误

C++ 从DLL导出STL std::basic_字符串模板时,出现LNK2005错误,c++,visual-studio-2010,dll,stl,C++,Visual Studio 2010,Dll,Stl,好的,我已经读了一些关于这个主题的问题和文章,我觉得我理解基本原理,但我仍然有困难 我有一个DLL,它导出一个以std::string作为成员的类。 我的主程序包含也有字符串的类,它使用DLL 如果我在VS2010中编译DLL,会收到以下警告: warning C4251: 'MyClass::data' : class 'std::basic_string<_Elem,_Traits,_Ax>' needs to have dll-interface to be used by c

好的,我已经读了一些关于这个主题的问题和文章,我觉得我理解基本原理,但我仍然有困难

我有一个DLL,它导出一个以std::string作为成员的类。 我的主程序包含也有字符串的类,它使用DLL

如果我在VS2010中编译DLL,会收到以下警告:

warning C4251: 'MyClass::data' : class 'std::basic_string<_Elem,_Traits,_Ax>' needs to have dll-interface to be used by clients of class 'MyClass'
EXPIMP_TEMPLATE template class DECLSPECIFIER std::allocator<char>;
EXPIMP_TEMPLATE template class DECLSPECIFIER std::basic_string< char, std::char_traits<char>, std::allocator<char> >;
警告C4251:'MyClass::data':类'std::basic_string'需要具有dll接口才能由类'MyClass'的客户端使用
当我编译EXE时,我得到相同的警告,但没有错误,程序编译并运行。事实上,这是一个大项目,所以我收到了大约40条警告,我对此不太感兴趣。(作为旁白,使用VS2008编译时,这些警告不存在)

因此,我读到了这条警告,它让我看到了这篇微软的文章: 它告诉我如何从DLL导出STL模板以满足我收到的警告

问题是,当我添加以下行以删除警告时:

warning C4251: 'MyClass::data' : class 'std::basic_string<_Elem,_Traits,_Ax>' needs to have dll-interface to be used by clients of class 'MyClass'
EXPIMP_TEMPLATE template class DECLSPECIFIER std::allocator<char>;
EXPIMP_TEMPLATE template class DECLSPECIFIER std::basic_string< char, std::char_traits<char>, std::allocator<char> >;
EXPIMP_模板模板类DECLSPECIFIER std::allocator; EXPIMP_模板模板类DECLSPECIFIER std::basic_string; DLL编译时没有警告,但当我编译EXE时,链接器会抛出一个错误:

2>SampleDLL.lib(SampleDLL.dll) : error LNK2005: "public: __thiscall std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::~basic_string<char,struct std::char_traits<char>,class std::allocator<char> >(void)" (??1?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ) already defined in OtherClass.obj
2>SampleDLL.lib(SampleDLL.dll) : error LNK2005: "public: unsigned int __thiscall std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::size(void)const " (?size@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBEIXZ) already defined in OtherClass.obj
2>SampleDLL.lib(SampleDLL.dll):错误LNK2005:“public:\uu thiscall std::basic\u string::~basic\u string(void)”(??1?$basic_string@DU?$char_traits@D@性病病毒$allocator@D@2@@std@@QAE@XZ)已在OtherClass.obj中定义
2> lib(SampleDLL.dll):错误LNK2005:“public:unsigned int\uu thiscall std::basic\u string::size(void)const”(?size@?$basic_string@DU?$char_traits@D@性病病毒$allocator@D@2@@std@@QBEIXZ)已在OtherClass.obj中定义
DLL和EXE都使用相同的代码生成选项编译。我可以在两者或MD上使用MT,结果是相同的

我将包含一个最小化的示例程序中的代码,以防我遗漏了上面的任何内容

我的主要问题是:我是否可以修复LNK2005错误,或者忽略C4251警告是否安全?

编辑:所以我读了更多的内容,看起来如果DLL类使用的std::string是一个只能由成员函数访问的私有变量,那么可以安全地忽略警告。。。对此有何评论?这是朝着正确的方向迈出的一步吗

DLL代码:

#pragma一次
#包括
#包括
#ifdef SAMPLEDLL_导出
#定义DECLSPECIFIER\uuu declspec(dllexport)
#定义EXPIMP_模板
#否则
#定义DECLSPECIFIER\uuu declspec(dllimport)
#定义EXPIMP_模板外部
#恩迪夫
//在模板实例化之前禁用外部警告(根据MS KB文章)
#杂注警告(禁用:4231)
//std::basic_字符串依赖于此分配器,因此它也必须导出。
EXPIMP_模板模板类DECLSPECIFIER std::allocator;
//string是一个typedef,因此不能导出它。您必须导出std::basic\u字符串
EXPIMP_模板模板类DECLSPECIFIER std::basic_string;
#杂注警告(默认值:4231)
类DECLSPECIFIER MyClass
{
公众:
std::string getData();//返回CPP文件中的'data',正文
私人:
std::字符串数据;
int数据2;
};
//在SampleDLL.cpp文件中。。。
std::string MyClass::getData(){return data;}
EXE代码:

#包括
#包括“SampleDLL.h”
使用名称空间std;
void main()
{
我的班级1;

cout您似乎看到了上描述的问题

这里建议了一个解决办法,但似乎有点令人讨厌

其他可能有帮助的选择:

  • 不要导出std::string,而是在DLL接口中使用const char*(请参阅)
  • 确保所有项目的_迭代器_调试_级别匹配

  • 您提交的MS文章的链接表示,一些STL类“…已经由C运行时DLL导出。因此,您无法从DLL导出它们。”。包括基本字符串。您的链接错误表示基本字符串符号“…已经在OtherClass.obj中定义”。因为链接器在两个不同的位置看到两个相等的符号

    从DLL导出STL std::basic_字符串模板时,出现LNK2005错误

    另请参阅Microsoft的KB 168958文章。从文章中:

    导出STL类

  • 在DLL和.exe文件中,链接到C运行时的同一DLL版本。或者链接到Msvcrt.lib(发布版本)或者 将两者链接到msvctd.lib(调试生成)
  • 在DLL中,在模板实例化声明中提供_declspec说明符,以便从中导出STL类实例化 动态链接库
  • 在.exe文件中,在模板实例化声明中提供extern和_declspec说明符,以从 这将导致警告C4231“使用了非标准扩展: 模板显式实例化之前的“extern”。“您可以忽略此项 警告

  • 我有一个黑客可以用temp解决这个问题

    打开项目选项,单击链接器->命令行, 在“附加选项”输入框中,键入

     /FORCE:MULTIPLE
    

    对我来说,整个话题归结为

    • 不要导出STL内容。忽略警告。(至少在MSVC2013之前。)
    • 当然,要确保各方都以相同的方式链接到C运行时,包括调试/发布、静态/动态
    到目前为止,我一直在解决这个问题


    不幸的是,如果您无法控制要链接到的源代码,那么这不是答案。

    Mark的可能副本:我确实读过这个问题,但它似乎没有对我看到的问题给出答案,因为它没有提到我现在遇到的额外LNK2005问题。谢谢。这显然是我遇到的问题寻找一条死线的方法,但答案就是答案,这就是答案