[erledigt] Speicher allokieren in C++/CLI



  • Hallo,

    ich habe gerade ein Verständnisproblem mit dem Aufruf einer normalen C-Funktion. Der Prototyp sieht folgendermasen aus:

    int
    Tcl_LinkVar(Tcl_Interp *interp, const char *varName, char *addr, enum type)
    

    Es handelt sich um eine Funktion, die in einem Tcl-Interpreter C-Variablen mit Tcl-Variablen verbindet. Man sollte dabei den Speicher für char *addr mit malloc allokieren, damit der Interpreter bei Änderung der Variablen mit free den Speicher freigeben kann und mit alloc auf einen neuen Speicher zeigen kann, der dann einen neuen String repräsentiert.

    Jetzt bin ich mir nicht sicher, ob man überhaupt noch mit malloc arbeiten soll. Es wird ja Speicher reserviert, aber wärend der Interpreter läuft, könnte der GC den Speicher umschichten und der Zeiger zeigt auf einmal ins Nirwana.

    Mit einem pin_ptr<char> könnte man dafür sorgen, dass das nicht passieren kann, aber leider bekomme ich dann zur Laufzeit die Fehlermeldung :

    Eine nicht behandelte Ausnahme des Typs "System.AccessViolationException" ist in SETclClr.dll aufgetreten.

    Zusätzliche Informationen: Es wurde versucht, im geschützten Speicher zu lesen oder zu schreiben. Dies ist häufig ein Hinweis darauf, dass anderer Speicher beschädigt ist.

    Wie behandle ich am besten so ein Problem?



  • Ich seh schon, diese Konzepte wie pin_ptr usw. bereiten dir einiges an Kopfzerbrechen. Grundsätzlich gilt bei C++/CLI, dass du alles so machen kannst, wie es verlangt wird - und deshalb solltest du auch so machen. Sprich: Wenn Speicher mittels malloc allokiert werden soll, dann machst du das bitte auch. Die Verwendung eines pin_ptr in Kombination mit einem array zur Allokation von Speicher mittels gcnew ist nicht nur unnötig kompliziert, sondern ergibt auch keinerlei Sinn wenn er schlussendlich ja wieder mit free freigegeben wird. Die Freigabe von nicht richtig allokiertem Speicher, wie es bei dir irgendwo passiert resultiert vermutlich in deiner AccessViolationException (...die du auch nur wegen .NET zu sehen bekommst. Ohne die Runtime würden dir wohl einige andere Dinge um die Ohren fliegen, undefiniertes Verhalten ;)).

    Ganz abgsehen davon darfst du eben genau in diesem Fall keinen pin_ptr benutzen. Ich habe keine Ahnung wie Tcl_LinkVar intern funktioniert, aber ich gehe davon aus das intern einer nativer Zeiger auf deinen Speicher gespeichert wird. Nach dem Aufruf dieser Funktion wird der von dir übergebene pin_ptr aber eventuell ungültig, dein Zeiger zeigt ins Nichts, weil das Scope verlassen wird und der Destruktor von pin_ptr aufgerufen wird. Infolgedessen darf der GC deinen Speicher verschieben. Du könntest versuchen, deinen pin_ptr am Leben zu erhalten solange Tcl läuft. In Anbetracht der Alternativen ist das jedoch alles andere als sinnvoll...

    So drop it & allokier den Speicher wie immer per malloc und gut ist 😉



  • Vergiss pin_ptr in diesem Zusammenhang... Programmiere einfach so wie _ohne_ C++/CLI und konvertiere die Strings entsprechend!
    Siehe:
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-158664.html
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-158666.html



  • Der Code sieht im Moment so aus:

    char *cPtr;
    char szVarName[] = "source_0";
    cPtr = Tcl_Alloc(80);
    Tcl_LinkVar(interp, szVarName, cPtr, TCL_LINK_STRING);
    

    Statt Tcl_Alloc(80) habe ich auch malloc(80) ausprobiert. Beides führt bei Aufruf von Tcl_LinkVar(...) zu bekannter Fehlermeldung:

    Eine nicht behandelte Ausnahme des Typs "System.AccessViolationException" ist in SETclClr.dll aufgetreten.

    Zusätzliche Informationen: Es wurde versucht, im geschützten Speicher zu lesen oder zu schreiben. Dies ist häufig ein Hinweis darauf, dass anderer Speicher beschädigt ist.

    Ich bin der Meinung, dass ich es richtig gemacht habe. Diese Fehlermeldung war der Grund, warum ich auf die Idee gekommen bin, pin_ptr<char> zu verwenden. Dann kam die Fehlermeldung nicht mehr, geklappt hat das ganze aber auch nicht. Nach Ablauf des Tcl-Skripts stand nur Undefiniertes drin, bzw. bei Aufruf des Skripts kam ein Laufzeitfehler wegen beschädigtem Speicher (oder so ähnlich).



  • Hat sich erledigt. Das Problem lag in der Funktion.
    Der Aufruf muss heißen:

    char *cPtr;
    char szVarName[] = "source_0";
    cPtr = Tcl_Alloc(80);
    Tcl_LinkVar(interp, szVarName, (char *)&cPtr, TCL_LINK_STRING);
    

    In der Funktion wird neuer Speicher allokiert und deshalb kann sich der Pointer ändern.


Anmelden zum Antworten