C++: Mehrfache ungewollte Einbindung von namespace std [gelöst]

Nightshift

Grand Admiral Special
Mitglied seit
19.08.2002
Beiträge
4.447
Renomée
81
Standort
Tief im Weeeeeesss-teheheheeen ;-)
  • SIMAP Race
  • Spinhenge ESL
  • Docking@Home
  • BOINC Pentathlon 2011
  • BOINC Pentathlon 2012
  • BOINC Pentathlon 2013
Hallo zusammen,

folgendes Problem habe ich momentan:

Ich muss momentan fremde Sourcen benutzen, die zu ändern keine Option darstellt.
Irgendwo in diesen Sourcen wird der namespace std eingebunden, aber leider so, dass bei weiterer Einbindung an anderer Stelle, also in meinem Source, Kollisionen durch die mehrfache Einbindung entstehen.

Jetzt gibt es ja verschiedene Methoden mit denen man die eigene using-Deklarative unterbinden kann, falls sie bisher schon einmal vorkam. Bis auf "ifndef" hab ich da schon das eine oder andere probiert, aber bisher ohne Erfolg. #ifndef wäre meine letzte Option, aber hierfür kenne ich den entsprechenden Token/Makro für namespace std nicht und die Suchmaschine wirft mir da bisher auch nichts Gescheites aus.

Ausserdem könnte es ein Problem zu sein, dass der genutzte Source schon vor meinem kompiliert und gebunden wird (geht leider nicht anders), d.h. dass meine Versuche zur Unterbindung der Mehrfacheinbindung eh zwecklos sein könnten.

Hat da jemand eine Idee zur Lösung des Problems?
Oder kennt jemand zumindest für den Anfang den Token/Makro zu namespace std den ich für das #ifndef benutzen kann?

Vielen Dank schon einmal im Voraus. :)
 
Zuletzt bearbeitet:
Hallo,

ich verstehe grad das Problem noch nicht so ganz. In den Header-Dateien, des vorhanden Sourcecodes werden Header aus der C++-Library wie std::string, std::map, std::list usw. eingebunden richtig? Und in deinem Code bindest du diese Header auch ein?
Normalesweise sollte das keine Probleme erzeugen. In den Headern wird doch mit #pragma once bzw. #ifndef gearbeitet um doppeltes Einbinden zu verhindern.
Oder geht es um using namespace std? Gib mal bitte ein paar mehr Infos, wenn möglich ein paar Codeauschnitte. Falls du den Code nicht veröffentlichen darfst, kannst du ihn ja auch verfremden, so dass keine wichtigen Details verraten werden.

Grüße

Marcel
 
Hey,

doch, hast es schon ganz richtig verstanden:
Genau, es werden im fremden Code std-Direktiven eingebunden. Ob nun einzeln (also z.B. using std::string) oder per "using namespace std" als ganzes kann ich leider nicht sagen, da mir der Compiler nur eine allgemeine Fehlermeldung auswirft und auf die Fremdcode-Libs verweist mit denen es dann zur Kollision kommt. Kann den eigentlichen Code also nicht sehen.
Deswegen kann ich leider auch nicht sagen, ob und wo genau im fremdem Code mit #pragma once oder #ifndef gearbeitet wird.

Ich selber habe die std-Direktiven zuerst einzeln eingebunden wie üblich (inkl. pragma once, für ifndef kenn ich ja die Makros nicht) und als das den Fehler produzierte auch testweise einmal per "using namespace std", es läuft in beiden Fällen auf dieselbe Fehlermeldung hinaus.

Detaillierte Fehlermeldung und evtl. Codesnippets kann ich am Montag posten.
 
Zuletzt bearbeitet:
Hier gibt es wohl ein paar Verwirrungen: Header bindet man mit "#include" ein, "using namespace" erlaubt nur das Weglassen des namespaces beim Benutzen der eingebundenen Objekte (also vector statt std::vector). Beide Sachen haben nichts miteinander zu tun, bewirken komplett verschiedene Dinge und führen in diesem Fall auch nicht zu Kollisionen.

Ich vermute hier wird einfach eine Compiler-Fehlermeldung falsch interpretiert. Wahrscheinlich wurde die Library mit einer anderen Runtime kompiliert, was dann zu Fehlermeldungen wie "std::vector irgendwas already defined in irgendeine.obj" führt. Daher einfach mal schauen ob die Runtimes übereinstimmen und/oder die genaue Fehlermeldung posten.
 
Zuletzt bearbeitet:
Hallo,

genau sowas würde ich auch vermuten. Normalesweise dürfte es beim mehrmaligen Einbinden von Headern nicht zu doppelten Definitionen kommen, da dies normalerweise durch entsprechende Präprozessor-Konstrukte abgefangen wird.
Deine Fehlermeldungen sind warscheinlich Linkerfehler, weil wie schon erwähnt gegen verschiedene Versionen der library gelinkt wurde.
Hast du den Quellcode für die externe Library vorliegen? Dann würde ich die auch mal neu kompilieren und darauf achten, das die gelinkten Libraries die gleichen sind wie die, die in deinem Programm verwendest.

Grüße

Marcel
 
Danke euch beiden, da habe ich mich in der Tat von der Fehlermeldung in die Irre leiten lassen.
Dann hab ich ja nun einen neuen Ansatzpunkt nach dem Fehler zu suchen. :)
 
So, der Lösungsansatz war in der Tat der richtige und hat mir weitergeholfen. :)

Bin aber nur wenig später gleich in ein neues Problem gelaufen:

2>msvcprtd.lib(MSVCP100D.dll) : error LNK2005: "public: __thiscall std::_Container_base12::~_Container_base12(void)" (??1_Container_base12@std@@QAE@XZ) ist bereits in ***.lib(***.obj) definiert.
2>msvcprtd.lib(MSVCP100D.dll) : error LNK2005: "public: __thiscall std::_Container_base12::_Container_base12(void)" (??0_Container_base12@std@@QAE@XZ) ist bereits in ***.lib(***.obj) definiert.
2>msvcprtd.lib(MSVCP100D.dll) : error LNK2005: "public: void __thiscall std::_Container_base12::_Orphan_all(void)" (?_Orphan_all@_Container_base12@std@@QAEXXZ) ist bereits in ***(***.obj) definiert.
2>fatal error LNK1169: Mindestens ein mehrfach definiertes Symbol gefunden.

Das ganze passiert durch folgende Zeile:
Code:
ofstream outstr;

Wenn ich das also richtig verstehe, dann findet der Linker das Symbol sowohl in der msvcprtd.lib als auch in meiner, korrekt?

Das Problem tritt übrigens nur in der "Debug"-Konfiguration auf, während es bei "Release" nicht existiert.
Kann ich dazu Vorgaben in den Linker/Compiler-Einstellungen vorgeben, die das Problem beheben?
 
Hi,

wenn es nur in Debug auftritt liegt es warscheinlich daran, dass du die Library auch nochmal im Debug-Modus bauen musst. Dein Programm wird gegen die Debug-Version der MSVCP gelinked und deine Library ist gegen die Release-Version gelinked. Dadurch bindest du 2 unterschiedliche Versionen der gleichen Klassen/Funktionen ein.

Grüße

Marcel
 
N'Abend!

Ja, das hatte ich danach auch vermutet und seitdem mehrmals das Projekt komplett neu erstellt, inkl. der Libs & alle Projektteile jeweils auf Debug, aber keine Änderung.

Ich meine, ich kann natürlich dem Compiler sagen er soll das ignorieren, aber lieber wäre es mir, wenn ich das Problem im Code selber lösen kann. ;)

Kann die Reihenfolge beim Linken eine Rolle spielen? Dass ich durch die Lib vom Projekt eine Definition der msvcprtd.lib überschreibe beim Linken?
 
Hi,

also die Linkreihenfolge spielt soweit ich weißt nur eine Rolle, wenn man den Incremental Linker deaktiviert. Aber auch, wenn der Incremental Linker deaktiviert ist, dürften keine Probleme mit doppelten Symbolen auftreten. Wenn dann werden Symbole nicht gefunden, weil eine Library noch nicht eingebunden ist, die von einer anderen Library benötigt wird.
Ignorieren kann man die Probleme nicht, sind ja keine Warnings. Es liegt auch nicht am Code sondern an deinen Projekteinstellungen.

Grüße

Marcel

Edit: was natürlich sein kann ist das der std::ofstream in der von dir eingebundenen Library selbst implementiert wurde. Zu Debuggingzwecken zum Beispiel. Kannst du in den Sourcecode der Library schauen? Dann schau mal ob da eine Implementierung für die std::ofstream im Code ist. Ich hatte was ähnliches mal bei der Open Source Library OpenSceneGraph. Da wurde auch der fstream neu implementiert. Da muss man aufpassen, dass nicht gegen die standard libraries von Microsoft gelinkt wird. Das kann man im Projekt ausschalten.
 
Zuletzt bearbeitet:
Hab den Fehler gefunden. Und er ist so doof - bzw. derjenige der da die Einstellung versemmelt hat, also ich ;D - ,dass es fast schon zu peinlich ist zu sagen woran es lag. o_O
Klassischer Fall von "den Wald vor lauter Bäumen nicht mehr sehen" ;):

Hatte die Laufzeitbibliothek noch auf /MDd stehen anstatt auf /MTd. Dadurch wird ja soweit ich weiß die MSVCRTD.lib vom Compiler mit in das .obj-File eingebunden und voila - man bekommt das bisherige Problem.
Bei /MTd ist das dann glaube ich die LIBCMTD.lib, durch die dann externe Symbole aufgelöst können werden sollten. -> Problem nicht mehr vorhanden

Also danke für die Wegweiser durch den Wald, haben mich letztendlich ans Ziel geführt. :)
 
Hallo,

das ist doch super, das es jetzt geklappt hat. Der Unterscheid zwischen den Einstellungen ist, dass /MDd die Standard-Library statisch linkt(der auszuführende Code als direkt in der exe ist) und /MTd dynamisch linkt(also nur Verweise auf eine DLL in das Programm gelinked werden). Wenn man einmal so und einmal so linkt hat man natürlich das Problem, dass der Linker nicht weiß, ob er jetzt statisch oder dynamisch linken soll, weil ja beides verwendet wurde.

Grüße

Marcel
 
Also ich würde gar kein "using namespace std;" verwenden kann besonders bei Biblotheken kann es zu Problemen führen.

Aus meiner Sicht macht "using namespace " nur Sinn wenn man im Code einen eigenen Namespaces deklariert hat.
 
Wie schon gesagt...
Ich selber habe die std-Direktiven zuerst einzeln eingebunden wie üblich [...] auch testweise einmal per "using namespace std", es läuft in beiden Fällen auf dieselbe Fehlermeldung hinaus.
Wobei es ja am Ende sowieso nicht am Namespace lag.
 
Zurück
Oben Unten