OK, so I've read several question and articles about this topic, and I feel like I understand the basics, but I'm still having trouble.
I have a DLL that exports a class that has a std::string as a member. My main program contains classes that also have strings, and it uses the DLL.
If I compile the DLL in VS2010, I get the following warnings:
warning C4251: 'MyClass::data' : class 'std::basic_string<_Elem,_Traits,_Ax>' needs to have dll-interface to be used by clients of class 'MyClass'
When I compile the EXE, I get the same warnings, but there are no errors, and the program compiles and runs. In reality, it's a large project, so I get like 40 warnings, and I'm not too keen on that. (As a side-observation, these warnings are not present when compiled with VS2008)
So, I read about that warning, and it lead me to this MS article: http://support.microsoft.com/default.aspx?scid=KB;EN-US;168958 which tells how to export a STL template from a DLL to satisfy the warnings I was getting.
The problem is, when I add the following lines to remove the warnings:
EXPIMP_TEMPLATE template class DECLSPECIFIER std::allocator<char>;
EXPIMP_TEMPLATE template class DECLSPECIFIER std::basic_string< char, std::char_traits<char>, std::allocator<char> >;
the DLL compiles with no warnings, but when I compile my EXE, the linker throws a fit:
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
Both the DLL and the EXE are compiled with the same code generation options. I can use MT on both or MD, and the results are the same.
I am including the code from a minimized sample program in case I left anything out above.
My main question: Can I fix the LNK2005 errors, or is it safe to just ignore the C4251 warnings?
Edit: So I've read a little more, and it looks like if the std::string that the DLL class uses is a private variable that is only accessed by member functions, it may be safe to ignore the warning... Any comments on this? Is this a step in the right direction?
DLL code:
#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 code:
#include <iostream>
#include "SampleDLL.h"
using namespace std;
void main()
{
MyClass class1;
cout << class1.getData() << endl;
}
It looks like you are seeing the issue described on connect.microsoft.com.
There is a workaround suggested there, but it seems a bit nasty.
Other options that might help:
Link to MS article that you presented says that some STL classes "...are already exported by the C Runtime DLL. Therefore, you cannot export them from your DLL. ". Including basic_string. And your link error says that basic_string symbol "...already defined in OtherClass.obj". Because linker sees two equal symbols in two different places.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With