当从DLL导出STL std::basic_string模板时,我得到一个LNK2005错误
When exporting STL std::basic_string template from DLL, I get a LNK2005 error
好的,所以我已经读了几个关于这个主题的问题和文章,我觉得我理解了基本知识,但我仍然遇到了麻烦。
我有一个DLL,它导出一个以std::字符串为成员的类。我的主程序包含也有字符串的类,它使用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'
当我编译EXE时,我会得到同样的警告,但没有错误,并且程序会编译并运行。事实上,这是一个大项目,所以我收到了大约40条警告,我对此并不太感兴趣。(作为一个侧面观察,当与VS2008一起编译时,这些警告不存在)
所以,我读到了这个警告,它让我看到了MS的这篇文章:http://support.microsoft.com/default.aspx?scid=KB;EN-US;168958它告诉如何从DLL导出STL模板以满足我收到的警告。
问题是,当我添加以下行以删除警告时:
EXPIMP_TEMPLATE template class DECLSPECIFIER std::allocator<char>;
EXPIMP_TEMPLATE template class DECLSPECIFIER std::basic_string< char, std::char_traits<char>, std::allocator<char> >;
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
DLL和EXE都使用相同的代码生成选项进行编译。我可以在两者上使用MT,也可以在MD上使用,结果是一样的。
我包含了一个最小化的示例程序的代码,以防我遗漏了上面的任何内容。
我的主要问题是:我可以修复LNK2005错误吗?或者忽略C4251警告是否安全
编辑:所以我读了更多,看起来如果DLL类使用的std::string是一个只有成员函数才能访问的私有变量,那么忽略警告可能是安全的。。。对此有何评论?这是朝着正确方向迈出的一步吗?
DLL代码:
#pragma once
#include <exception>
#include <string>
#ifdef SAMPLEDLL_EXPORTS
# define DECLSPECIFIER __declspec(dllexport)
# define EXPIMP_TEMPLATE
#else
# define DECLSPECIFIER __declspec(dllimport)
# define EXPIMP_TEMPLATE extern
#endif
//disable warnings on extern before template instantiation (per MS KB article)
#pragma warning (disable : 4231)
//std::basic_string depends on this allocator, so it must also be exported.
EXPIMP_TEMPLATE template class DECLSPECIFIER std::allocator<char>;
//std::string is a typedef, so you cannot export it. You must export std::basic_string
EXPIMP_TEMPLATE template class DECLSPECIFIER std::basic_string< char, std::char_traits<char>, std::allocator<char> >;
#pragma warning (default : 4231)
class DECLSPECIFIER MyClass
{
public:
std::string getData(); //returns 'data', body in CPP file
private:
std::string data;
int data2;
};
//in SampleDLL.cpp file...
std::string MyClass::getData() { return data; }
EXE代码:
#include <iostream>
#include "SampleDLL.h"
using namespace std;
void main()
{
MyClass class1;
cout << class1.getData() << endl;
}
您似乎看到了connect.microsoft.com上描述的问题。
这里有一个变通办法,但似乎有点令人讨厌。
其他可能有帮助的选项:
- 不要导出std::string,而是在DLL接口中使用const char*(请参阅https://stackoverflow.com/a/5340065/12663)
- 确保_ITERATOR_DEBUG_LEVEL与您的所有项目相匹配
您提交的MS文章链接说,一些STL类"…已经由C运行时DLL导出。因此,您无法从DLL导出它们。"。包括basic_string。您的链接错误显示basic_string符号"…已在OtherClass.obj中定义"。因为链接器在两个不同的位置看到两个相等的符号。
当从DLL导出STL std::basic_string模板时,我得到一个LNK2005错误
另请参阅Microsoft的KB 168958文章"如何导出标准模板库(STL)类和包含STL对象数据成员的类的实例化"。来自文章:
导出STL类
- 在DLL和.exe文件中,使用C运行时的相同DLL版本进行链接。请使用Msvcrt.lib(发布版本)链接两者,或者将两者与Msvcrtd.lib(调试构建)链接
- 在DLL中,在模板实例化声明中提供__declspec说明符,以从导出STL类实例化DLL
- 在.exe文件中,在模板实例化声明中提供extern和__declspec说明符,以从DLL。这将导致警告C4231"使用了非标准扩展:模板显式实例化之前的"extern"。"你可以忽略这个警告
我得到了一个破解,可以在临时中修复这个问题
打开"项目选项",单击"链接器"->"命令行",在附加选项输入框中,键入
/FORCE:MULTIPLE
对我来说,整个主题归结为
- 不要导出STL内容。忽略警告。(至少在MSVC2013之前。)
- 当然,要确保每一方都以与调试/发布、静态/动态相同的方式链接到C运行时
到目前为止一直为我解决这个问题。
不幸的是,如果您无法控制要链接到的源代码,那就没有答案。
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 运行同一解决方案的另一个项目的项目
- 挂起和取消挂起一个文件DLL
- 用C++中的一个变量定义一个常量
- 函数向量_指针有不同的原型,我可以构建一个吗
- 在c++中用vector填充一个简单的动态数组
- 如何在选项卡视图Qt中设置一个新项目,并保存以前的项目
- 预处理器:插入结构名称中的前一个行号
- 我在c++代码中生成了一个运行时#3异常
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 从链接列表c++中删除一个项目
- 告诉一个 const char 数组,除了编译时 C 样式的字符串外,它不以 '