17 Stimmen

Auswirkungen der Verwendung von std::vector in einer von der DLL exportierten Funktion

Ich habe zwei dll-exportierte Klassen A und B. Die Deklaration von A enthält eine Funktion, die einen std::vector in ihrer Signatur wie verwendet:

class EXPORT A{
 // ...
 std::vector<B> myFunction(std::vector<B> const &input);
};

(EXPORT ist das übliche Makro zum Einfügen _ declspec(dllexport)/ _declspec(dllimport) entsprechend.)

Wenn ich über die Probleme lese, die mit der Verwendung von STL-Klassen in einer DLL-Schnittstelle verbunden sind, kann ich zusammenfassend feststellen:

  • Die Verwendung von std::vector in einer DLL-Schnittstelle würde erfordern, dass alle Clients dieser DLL mit der gleichen Version des gleichen Compilers, da STL-Container nicht binärkompatibel sind. Schlimmer noch, je nach Verwendung dieser DLL durch Clients zusammen mit anderen DLLs kann die "instabile" DLL-API diese Client-Anwendungen zerstören, wenn Systemaktualisierungen (z. B. Microsoft KB-Pakete) installiert werden (wirklich?).

  • Trotzdem kann std::vector bei Bedarf in einer DLL-API verwendet werden, und zwar durch den Export von std::vector<B> mögen:

    template class EXPORT std::allocator<B>;
    template class EXPORT std::vector<B>;

    Allerdings wird dies normalerweise in dem Zusammenhang erwähnt, wenn man std::vector als Mitglied von A (http://support.microsoft.com/kb/168958).

  • Der folgende Microsoft Support-Artikel beschreibt, wie man auf std::vector-Objekte, die in einer DLL erstellt wurden, über einen Zeiger oder Verweis aus der ausführbaren Datei heraus zugreifen kann (http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q172396). Die obige Lösung zur Verwendung von template class EXPORT ... scheint ebenfalls anwendbar zu sein. Der unter dem ersten Aufzählungspunkt zusammengefasste Nachteil scheint jedoch bestehen zu bleiben.

  • Um das Problem vollständig zu beseitigen, müsste man std::vector einpacken und die Signatur von myFunction , PIMPL usw..

Meine Fragen sind:

  • Ist die obige Zusammenfassung richtig, oder übersehe ich hier etwas Wesentliches?

  • Warum erzeugt die Kompilierung meiner Klasse 'A' nicht die Warnung C4251 (class 'std::vector<_Ty>' needs to have dll-interface to be used by clients of...)? Ich habe keine Compiler-Warnungen ausgeschaltet und erhalte keine Warnung bei der Verwendung von std::vector in myFunction in der exportierten Klasse A (mit VS2005).

  • Was muss für den korrekten Export getan werden? myFunction in A? Ist es praktikabel, einfach zu exportieren std::vector<B> und dem Zuweiser von B?

  • Was sind die Auswirkungen der Rückgabe von std::vector by-value? Angenommen, eine ausführbare Client-Datei wurde mit einem anderen Compiler (-version) kompiliert. Bleibt das Problem bestehen, wenn der Vektor bei der Rückgabe von by-value kopiert wird? Ich denke ja. Ähnliches gilt für die Übergabe von std::vector als konstante Referenz: könnte der Zugriff auf std::vector<B> (die möglicherweise von einer ausführbaren Datei erstellt wurde, die mit einem anderen Compiler (-version) kompiliert wurde) führen zu Problemen in myFunction ? Ich denke, ja wieder.

  • Ist der letzte oben genannte Punkt wirklich die einzige saubere Lösung?

Vielen Dank im Voraus für Ihr Feedback.

0 Stimmen

Der folgende Thread behandelt einige/verwandte Fragen, aber nicht alle Gewinde

0 Stimmen

Template class EXPORT std::vector<B>; funktioniert, um alle Mitgliedsfunktionen richtig zu exportieren/importieren. Was ist mit Template-Funktionen, die keine Member-Funktionen sind? Z.B. operator==()? Beginnend mit VS 2012, erhalte ich jetzt Verknüpfungsfehler beim Erstellen der DLL, weil die Vektorvergleichsfunktion undefiniert ist.

0 Stimmen

Empfohlene weiterführende Lektüre: stackoverflow.com/q/5347355/103167

2voto

Sergey Kalinichenko Punkte 694383

Leider ist Ihre Liste sehr zutreffend. Die Hauptursache dafür ist, dass DLL-zu-DLL oder DLL-zu-EXE auf der Ebene des Betriebssystems definiert ist, während die Schnittstelle zwischen Funktionen auf der Ebene eines Compilers definiert ist. In gewisser Weise ist Ihre Aufgabe ähnlich (wenn auch etwas einfacher) wie die der Client-Server-Interaktion, wenn Client und Server nicht binär kompatibel sind.

Der Compiler ordnet das, was er kann, der Art und Weise zu, wie der DLL-Import und -Export in einem bestimmten Betriebssystem durchgeführt wird. Da die Sprachspezifikationen den Compilern viele Freiheiten lassen, wenn es um das binäre Layout von benutzerdefinierten Typen und manchmal sogar von eingebauten Typen geht (denken Sie daran, dass die genaue Größe von int ist compilerabhängig, solange die Mindestanforderungen an die Größe erfüllt sind), muss das Importieren und Exportieren aus DLLs manuell erfolgen, um Kompatibilität auf binärer Ebene zu erreichen.

Wenn Sie dieselbe Version desselben Compilers verwenden, stellt dieser letzte Punkt kein Problem dar. Sobald jedoch ein anderer Compiler ins Spiel kommt, ist alles anders: Sie müssen zu den einfach getippten Schnittstellen zurückkehren und Wrapper einführen, um schön aussehende Schnittstellen in Ihrem Code zu erhalten.

0 Stimmen

Mmmh.. aber das würde bedeuten, dass die gleichen Probleme bestehen, wenn ich die std::vector<B> avec int ? Oder bis zu welchem Punkt schafft es das Betriebssystem, Typen zuzuordnen?

0 Stimmen

@user1043103 Bei meinem letzten C-Job hatten wir Codierungsstandards, die die Verwendung von nur #define -d-Typen in Signaturen von Funktionen, die wir aus unseren DLLs exportiert haben, und vermeiden dabei eingebaute Primitive. Zum Beispiel sollten wir Folgendes verwenden INT32 anstelle von int - vermutlich, um die Kompatibilität zwischen verschiedenen Versionen eines Compilers zu erhalten.

0voto

Patrick Bangert Punkte 83

Ich hatte das gleiche Problem und habe eine gute Lösung dafür gefunden.
Anstatt die std:vector können Sie eine QVector von der Qt Bibliothek.
Die von Ihnen genannten Probleme werden dann innerhalb der Qt Bibliothek und Sie brauchen sich nicht damit zu befassen.
Der Preis dafür ist natürlich, dass man die Bibliothek verwenden und ihre etwas schlechtere Leistung akzeptieren muss.
In Anbetracht der Zeitersparnis bei der Programmierung und Fehlersuche lohnt sich diese Lösung auf jeden Fall.

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