从DLL导出STL std :: basic_string模板时,出现LNK2005错误

时间:2012-01-23 18:23:46

标签: 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 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都使用相同的代码生成选项进行编译。我可以在两者或MD上使用MT,结果是一样的。

如果我遗漏了任何内容,我会将最小化的示例程序中的代码包括在内。

我的主要问题:我可以解决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;

}

5 个答案:

答案 0 :(得分:3)

看起来您正在connect.microsoft.com上看到问题。

那里有一个解决方法,但似乎有点讨厌。

其他可能有用的选项:

  1. 不要导出std :: string,而是在DLL接口中使用const char *(参见https://stackoverflow.com/a/5340065/12663
  2. 确保_ITERATOR_DEBUG_LEVEL与所有项目匹配

答案 1 :(得分:2)

链接到您提供的MS文章说,某些STL类“...已经由C运行时DLL导出。因此,您无法从DLL中导出它们。”包括basic_string。并且您的链接错误表明basic_string符号“...已在OtherClass.obj中定义”。因为链接器在两个不同的位置看到两个相等的符号。

答案 2 :(得分:0)

  

从DLL导出STL std :: basic_string模板时,出现LNK2005错误

另请参阅Microsoft的KB 168958文章How to export an instantiation of a Standard Template Library (STL) class and a class that contains a data member that is an STL object。来自文章:

  

导出STL类

     
      
  1. 在DLL和.exe文件中,链接与C运行时的相同DLL版本。要么链接Msvcrt.lib(发布版本),要么   链接Msvcrtd.lib(调试版本)。
  2.   
  3. 在DLL中,在模板实例化声明中提供__declspec说明符以从中导出STL类实例化   DLL。
  4.   
  5. 在.exe文件中,在模板实例化声明中提供extern和__declspec说明符,以从中导入类。   DLL。这导致警告C4231“使用非标准扩展:   模板显式实例化之前的'extern'。“你可以忽略它   警告。
  6.   

答案 3 :(得分:0)

我有一个hack可以在temp中解决这个问题

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

 /FORCE:MULTIPLE

答案 4 :(得分:0)

对我而言,整个话题归结为

  • 不要导出STL内容。忽略警告。 (至少达到MSVC2013。)
  • 当然要确保每一方都以与调试/发布,静态/动态相同的方式链接到C运行时。

到目前为止,我总是为我解决问题。

不幸的是,如果您无法控制要链接的源代码,那就无法回答。

相关问题