Laufzeitfehler bei dll-Aufruf
-
Hi.
Hab mal wieder ein Verhalten in meinem Code, was ich mir nicht erklären kann.
Ich habe eine Klasse Laufzeitsystem. Dieses verwaltet ne ganze Menge anderer Objekte.Da ich das Laufzeitsystem über eine dll steuere, habe ich eine Datei interface.cpp mit Steuerungsfunktionen für das Laufzeitsystem:
// z.B. Laufzeitsystem lzs; DLL anlegen() { lzs = new Laufzeitsystem(); } DLL zerstoren() { delete lzs; } // Funktion leitet den Aufruf nur an das Laufzeitsystem durch DLL fuelleVector(vector<string>* _vec) { lzs->fuelleVector(_vec); }
Die Methode lzs->fuelleVector sieht abstrahiert so aus:
void lzs::fuelleVector(vector<string>* _vec) { _vec->push_back("4711"); }
Alles kompiliert problemlos. Nun gibt es zwei Varianten, wie ich die dll-Funktion aus meinem Anwendungsprogramm aufrufen kann:
//**************** //* Variante A vector<string> vec; fuelleVector(&vec); // ... Verarbeitung //**************** //* Variante B vector<string>* vec = new vector<string>; fuelleVector(vec); // ... Verarbeitung delete vec;
Beide Varianten funktionieren tadellos, die Werte sind vorhanden und können verarbeitet werden.
Nur wenn ich das Anwendungsprogramm beende bekomme ich bei Variante A
- "user called breakpoint at ..." (wenn ich es im VC++ 6.0 ausführe)
- "debug assertion failed" (wenn ich die *.exe in der Konsole ausführe)Warum ist das so? Eigentlich sollte es doch egal sein, ob der vector in meinem Anwendungsprogramm auf dem Stack oder auf dem Heap liegt?
/edit:
Wenn ich, wie oben in Variante B beschrieben "delete vec" aufrufe, kommt der gleiche Quatsch. Irgendwie hab ich einen großen Denkfehler drin...
-
Verwenden Hauptprogramm und DLL die gleiche Version der Runtime-DLLs?
-
Was genau meinst du mit Runtime-DLLs? Läuft alles auf dem gleichen Rechner.
-
Einfach ausgedrückt, wenn das Hauptprogramm als Release kompiliert ist, mußt du die zugehörige DLL auch im Release-Modus kompilieren.
Und bei Debug auch die DLL im Debug-Mode.Da du ja Speicherreservierungen -und zugriffe mal im Hauptprogramm und mal in der DLL vornimmst, müssen diese Versionen natürlich kompatibel zueinander sein.
Besser wäre es, wenn die Speicherreservierungen und schreibende Zugriffe in der DLL passieren, und du nur lesend von Hauptprgramm darauf zugreifst.
P.S. In der Debug-Variante wird noch zusätzlicher Speicher intern bei new angelegt (und bei push_back wird ja evtl. neuer Speicher reserviert)
-
Mittlerweile habe ich herausgefunden, dass der Fehler dann auftritt, wenn Speicher, der in der dll allokiert wurde freigegeben werden soll.
//**************** //* Variante A vector<string> vec; fuelleVector(&vec); // ... Verarbeitung
Hier wird das Objekt vec bei Verlassen des Programms automatisch zerstört, also wird auch versucht den in der dll allokierten Speicher freizugeben. Der Fehler tritt auf.
//**************** //* Variante B vector<string>* vec = new vector<string>; fuelleVector(vec); // ... Verarbeitung delete vec;
Hier wird das Objekt vec von mir mit delete zerstört, also wird auch versucht den in der dll allokierten Speicher freizugeben. Der Fehler tritt auf.
Eine Vermutung:
Sonst treten "Debug Assertion"-Fehler auf, wenn man versucht Speicher freizugeben, der nicht allokiert war. Also wenn man zum Beispiel "delete vec" aufruft, bevor man mit "new vector.." Speicher allokiert hat.Das würde aber bedeuten, dass in der dll der genutzte Speicher automatisch wieder freigegeben wird.
Ich bin verwirrt.
-
Speicher der in der dll alloziert wurde muß auch in der dll wieder freigegeben werden. Wenn das außerhalb passiert kann es ja sein, dass deiser Speicher nicht mehr gültig ist. Ich würde es an deiner Stelle sowieso vermeiden Referenzen oder Pointer auf Stack-variablen in eine dll zu übergeben. Klassen per copy lieber auch nicht.
-
Und wie bekomme ich meine Daten dann dynamisch aus der dll raus? Ich will nicht jedesmal einen genügend großen Puffer anlegen, wenn ich Daten haben will.
Und jedes Mal vorher eine Funktion aufrufen, die mir die benötigte Größe errechnet kommt auch nicht in Frage.
-
Übergib einen Pointer auf deine Variable erzeuge den notwendigen Speicher innerhalb der dll und achte halt drauf, dass du die dll nicht entlädst bevor du die Daten fertig verabeitet hast. Den Speicher musst du halt innerhalb der dll wieder freigeben.
-
Wie wäre es mit einer Klasse deren operator delete eine Funktion in der DLL aufruft, die den Speicher dort freigibt. Wenn Du einen Zeiger auf ein solches Objekt im Hauptprogramm löscht würden die Ressourcen innerhalb der DLL gelöscht (müsste doch gehen oder?!). Das ganze noch in einen Smartptr verpackt und Du hättest fast garkeine Speichersorgen mehr.
EDIT:
Hätte das mehr durchdenken sollen, das Destruktorproblem löst das freilich nicht.