C++ 从DLL导出STL std::basic_字符串模板时,出现LNK2005错误
好的,我已经读了一些关于这个主题的问题和文章,我觉得我理解基本原理,但我仍然有困难 我有一个DLL,它导出一个以std::string作为成员的类。 我的主程序包含也有字符串的类,它使用DLL 如果我在VS2010中编译DLL,会收到以下警告: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
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_string2>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问题。谢谢。这显然是我遇到的问题寻找一条死线的方法,但答案就是答案,这就是答案