Okay, also ich habe schon mehrere Fragen und Artikel zu diesem Thema gelesen und ich habe das Gefühl, dass ich die Grundlagen verstehe, aber ich habe immer noch Schwierigkeiten.
Ich habe eine DLL, die eine Klasse exportiert, die eine std::string als Member hat. Mein Hauptprogramm enthält Klassen, die auch Zeichenfolgen haben, und es verwendet die DLL.
Wenn ich die DLL in VS2010 kompiliere, erhalte ich die folgenden Warnungen:
Warnung C4251: 'MyClass::data' : Klasse 'std::basic_string<_Elem,_Traits,_Ax>' muss ein dll-Interface haben, um von Klienten der Klasse 'MyClass' verwendet zu werden
Wenn ich das EXE kompiliere, erhalte ich dieselben Warnungen, aber es gibt keine Fehler und das Programm kompiliert und läuft. In Wirklichkeit handelt es sich um ein großes Projekt, also erhalte ich etwa 40 Warnungen, und das gefällt mir nicht so gut. (Als Nebenbemerkung, diese Warnungen sind nicht vorhanden, wenn mit VS2008 kompiliert wird)
Also las ich über diese Warnung und das hat mich zu diesem MS-Artikel geführt: http://support.microsoft.com/default.aspx?scid=KB;EN-US;168958 der erklärt, wie man eine STL-Vorlage aus einer DLL exportiert, um die Warnungen, die ich erhalten habe, zu erfüllen.
Das Problem ist, wenn ich die folgenden Zeilen hinzufüge, um die Warnungen zu beseitigen:
EXPIMP_TEMPLATE template class DECLSPECIFIER std::allocator;
EXPIMP_TEMPLATE template class DECLSPECIFIER std::basic_string< char, std::char_traits, std::allocator >;
kompiliert die DLL ohne Warnungen, aber wenn ich meine EXE kompiliere, gibt der Linker einen Fehler aus:
2>SampleDLL.lib(SampleDLL.dll) : Fehler LNK2005: "public: __thiscall std::basic_string,class std::allocator >::~basic_string,class std::allocator >(void)" (??1?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ) bereits in OtherClass.obj definiert
2>SampleDLL.lib(SampleDLL.dll) : Fehler LNK2005: "public: unsigned int __thiscall std::basic_string,class std::allocator >::size(void)const " (?size@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBEIXZ) bereits in OtherClass.obj definiert
Sowohl die DLL als auch die EXE werden mit denselben Optionen zur Codegenerierung kompiliert. Ich kann auf beiden MT oder MD verwenden und die Ergebnisse sind gleich.
Ich füge den Code aus einem minimierten Beispielsprogramm ein, falls ich oben etwas ausgelassen habe.
Meine Hauptfrage: Kann ich die LNK2005-Fehler beheben, oder ist es sicher, die C4251-Warnungen zu ignorieren?
Bearbeitung: Also ich habe noch etwas mehr gelesen und es scheint, als ob, wenn die std::string, die die DLL-Klasse verwendet, eine private Variable ist, die nur von Memberfunktionen zugegriffen wird, es möglicherweise sicher ist, die Warnung zu ignorieren... Irgendwelche Kommentare dazu? Ist das ein Schritt in die richtige Richtung?
DLL-Code:
#pragma once
#include
#include
#ifdef SAMPLEDLL_EXPORTS
# define DECLSPECIFIER __declspec(dllexport)
# define EXPIMP_TEMPLATE
#else
# define DECLSPECIFIER __declspec(dllimport)
# define EXPIMP_TEMPLATE extern
#endif
//Warnungen bei extern vor Templatinstantiierung ausschalten (gemäß MS KB-Artikel)
#pragma warning (disable : 4231)
//std::basic_string ist von diesem Allocator abhängig, also muss er auch exportiert werden.
EXPIMP_TEMPLATE template class DECLSPECIFIER std::allocator;
//std::string ist ein typedef, also kann es nicht exportiert werden. Es muss std::basic_string exportiert werden
EXPIMP_TEMPLATE template class DECLSPECIFIER std::basic_string< char, std::char_traits, std::allocator >;
#pragma warning (default : 4231)
class DECLSPECIFIER MyClass
{
public:
std::string getData(); //gibt 'data' zurück, Implementierung in CPP-Datei
private:
std::string data;
int data2;
};
//in SampleDLL.cpp-Datei...
std::string MyClass::getData() { return data; }
EXE-Code:
#include
#include "SampleDLL.h"
using namespace std;
void main()
{
MyClass class1;
cout << class1.getData() << endl;
}