8 Stimmen

Beim Exportieren des STL-std::basic_string-Vorlagenformats aus einer DLL erhalte ich einen LNK2005-Fehler

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;

}

4voto

danio Punkte 8241

Es sieht so aus, als ob Sie das auf connect.microsoft.com beschriebene Problem sehen.

Dort wird ein Workaround vorgeschlagen, aber es scheint ein wenig unschön zu sein.

Weitere Optionen, die helfen könnten:

  1. Exportieren Sie kein std::string, verwenden Sie stattdessen const char * in der DLL-Schnittstelle (siehe https://stackoverflow.com/a/5340065/12663)
  2. Stellen Sie sicher, dass der _ITERATOR_DEBUG_LEVEL für alle Ihre Projekte übereinstimmt.

1voto

Vlad Novakovsky Punkte 1795

Der Link zum von Ihnen präsentierten MS-Artikel besagt, dass einige STL-Klassen "... bereits von der C-Runtime-DLL exportiert werden. Daher können Sie sie nicht aus Ihrer DLL exportieren. ". Dazu gehört auch basic_string. Und Ihr Linkfehler besagt, dass das basic_string-Symbol "... bereits in OtherClass.obj definiert ist". Der Linker sieht also zwei gleiche Symbole an zwei verschiedenen Orten.

0voto

jww Punkte 90029

Beim Exportieren der STL std::basic_string-Vorlage aus einer DLL erhalte ich einen LNK2005-Fehler

Siehe auch den Artikel 168958 von Microsoft KB So wird die Instanz eines Standard Template Library (STL)-Klasse und einer Klasse exportiert, die ein Datenmitglied enthält, das ein STL-Objekt ist. Aus dem Artikel:

Um eine STL-Klasse zu exportieren

  1. Verknüpfen Sie sowohl die DLL als auch die .exe-Datei mit derselben DLL-Version der C-Laufzeitbibliothek. Verknüpfen Sie entweder beide mit Msvcrt.lib (Release-Build) oder verknüpfen Sie beide mit Msvcrtd.lib (Debug-Build).
  2. Geben Sie in der DLL im Vorlagen-Instantiierungsdeklaration das __declspec-Schlüsselwort an, um die STL-Klassen-Instanz aus der DLL zu exportieren.
  3. Geben Sie in der .exe-Datei im Vorlagen-Instantiierungsdeklaration die externen und __declspec-Schlüsselwörter an, um die Klasse aus der DLL zu importieren. Dies führt zu einer Warnung C4231 "nicht standardmäßige Erweiterung verwendet: 'extern' vor template explicit instantiation." Diese Warnung kann ignoriert werden.

0voto

bowman han Punkte 1066

Ich habe einen Hack, der das vorübergehend fixen kann

Öffne Projektoptionen, klicke auf Linker -> Befehlszeile, Im Eingabefeld für zusätzliche Optionen, gib ein:

 /FORCE:MULTIPLE

0voto

yau Punkte 507

Für mich reduzierte sich das ganze Thema auf

  • Exportieren Sie keine STL-Sachen. Ignorieren Sie die Warnung. (Zumindest bis MSVC2013.)
  • Sorgen Sie natürlich dafür, dass jede Partei bezüglich Debug/Release, statisch/dynamisch auf dieselbe Weise auf das C-Laufzeitprogramm verweist.

Das hat das Problem für mich bisher immer gelöst.

Leider ist das keine Lösung, wenn Sie keinen Einfluss auf den Quellcode haben, den Sie verknüpfen möchten.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X