[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 mittelsmalloc
allokiert werden soll, dann machst du das bitte auch. Die Verwendung einespin_ptr
in Kombination mit einemarray
zur Allokation von Speicher mittelsgcnew
ist nicht nur unnötig kompliziert, sondern ergibt auch keinerlei Sinn wenn er schlussendlich ja wieder mitfree
freigegeben wird. Die Freigabe von nicht richtig allokiertem Speicher, wie es bei dir irgendwo passiert resultiert vermutlich in deinerAccessViolationException
(...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 wieTcl_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 übergebenepin_ptr
aber eventuell ungültig, dein Zeiger zeigt ins Nichts, weil das Scope verlassen wird und der Destruktor vonpin_ptr
aufgerufen wird. Infolgedessen darf der GC deinen Speicher verschieben. Du könntest versuchen, deinenpin_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.