Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Zeiger und der ^-Operator
fiore - Mi 09.09.09 15:00
Titel: Zeiger und der ^-Operator
Hallo!
Ich habe gerade in Delphi einen Fibonacci-Heap implementiert um mit dem Dijkstra-Algorithmus kürzeste Wege in Graphen schnell finden zu können. Allerdings habe ich das Problem, dass bei mehrmaligem Aufruf des Dijkstra-Algorithmus, und damit dem mehrfachen Auf- und Abbbau eines Fib-Heaps, mein Speicher extrem zugemüllt wird. Meine Versuche das Problem mit Dispose in den Griff zu kriegen haben bisher noch zu keinem Ergebnis geführt. Deshalb habe ich mich ein bisschen gelesen und bin auf folgendes Problem gestoßen:
Wofür ist der ^-Operator eigentlich genau da? Naiv wie ich war, habe ich meinen gesamten Fib-Heap nämlich ohne den ^-Operator aufgebaut und das funktioniert auch alles ohne Probleme. Allerdings habe ich die Vermutung, dass deshalb mein Dispose nicht ordentlich funktioniert. Liege ich mit der Vermutung richtig und wenn ja, an welchen Stellen muss ich den ^-Operator nehmen und an welchen nicht?
Vielen Dank!
fiore
PS: Bei Bedarf kann ich auch Quellcode-Schnipsel anhängen.
HelgeLange - Mi 09.09.09 15:22
Stell es Dir mit Pointer so vor : Ein Pointer zeigt auf die Hausadresse während Du noch am Bahnhof bist. Der ^-Operator ist das Taxi, das Dich vor dem Haus absetzt :)
Bsp in Delphi :
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| type RMeinRecord = packed record String1 : String; String2 : String; Integer1 : Integer; end; PMeinRecord = ^RMeinRecord;
procedure XYZ; var pData : PMeinRecord; begin New(pData); pData.String1 := 'Hallo'; pData^.String1 := 'Hallo'; Dispose(pData); end; |
Flamefire - Mi 09.09.09 15:26
Ich glaube bei Pointern auf records geht es auch ohne ^ da Delphi das intern dereferenziert, oder?
fiore - Mi 09.09.09 15:34
Also bei mir handelt es sich um Pointer auf records.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| type TZeiger = ^TKnotenh; TFibHeap = record min: TZeiger; n: integer; end; TKnotenh = record p, kind, links, rechts: TZeiger; grad: integer; marke: boolean; d: real; nr: integer; pred: integer; end; |
Heißt das dann also, dass es hier keine Probleme machen dürfte, dass ich das ^ überall weggelassen habe?
@ Helge: Dein Beispiel läuft mit beiden Zeilen. Was also genau ist an der ersten Zeile falsch bzw. was passiert in der ersten Zeile ohne ^ was in der anderen Zeile nicht passiert bzw. umgekehrt?
Martok - Mi 09.09.09 15:36
Flamefire hat folgendes geschrieben : |
| Ich glaube bei Pointern auf records geht es auch ohne ^ da Delphi das intern dereferenziert, oder? |
Ja. Der
.-Operator dereferenziert selber. Ist der gleiche Mechanismus, der auch auf Objekte angewendet wird, wenn man
foo.bar:= '123' schreibt.
Dispose hat damit erstmal genau nix zu tun... Das würde bestenfalls mit GC ne Rolle spielen.
Wie räumst du denn auf? Eventuell fehlt ja eine Ebene oder sowas...
fiore - Mi 09.09.09 15:40
Also aufräumen mache ich bisher wie folgt:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| var Q: TFibHeap; begin Q := make_fib_heap; [...] dispose(Q.min); end |
Dabei war TFibHeap wie folgt definiert:
Delphi-Quelltext
1: 2: 3: 4:
| TFibHeap = record min: TZeiger; n: integer; end; |
Was meinst du mit "vielleicht fehlt eine Ebene?"
Es kann natürlich auch sein, dass die Speicherplatzprobleme an einer anderen Stelle auftreten. Z.b. wenn ich das Minimum aus dem Fibonacci-Heap entferne.
Martok - Mi 09.09.09 15:42
Dann ist das schon klar. Du gibts einen Datenblock frei... was passiert mit den anderen? Nichts, genau. Die stehen immer noch irgendwo rum, nur, dass du nicht mehr weißt wo. Die Referenz hast du ja grade weg geworfen ;)
Du musst dich also den gesamten Baum durchhangeln und alle TZeiger in der richtigen Reihenfolge freigeben.
Darauf war auch das mit der fehlenden Ebene bezogen.
fiore - Mi 09.09.09 15:50
Ah alles klar. Ja das erklärt einiges :-)
Zum Glück habe ich schon eine Ausgabe-Prozedur, die sich durch den gesamten Heap schlängelt. Da brauch ich dir nur noch so umprogrammieren, dass alles gelöscht wird. Vielen Dank! Ich hoffe es klappt!
HelgeLange - Mi 09.09.09 15:57
Der Unterschied zwischen dem Record und dem Zeiger auf ein record is ja schon da. Auch wenn es Delphi mittlerweile vielleicht selbst dereferenziert, behalte ich ich die Schreibweise bei, da ich immer genau weis, ob ich mit einem Record oder dem Zeiger darauf arbeite.. bin halt old-school :)
Und die Frage, was ein ^-Operator macht, war ja da und ich habe sie beantwortet :P
OK, zum Problem.
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| var Q: TFibHeap; begin Q := make_fib_heap; [...] dispose(Q.min); end |
make_fib_heap erzeugt ja nicht nur ein TZeiger, sondern einen TFibHeap. Dein Dispose muss also auf Q sein und nicht nur auf ein Mitglied von Q. Dieses Q.Min musst Du natürlich auch freigeben mit Dispose.
fiore - Do 10.09.09 14:39
Vielen Dank euch nochmal!
Ich habe das Problem jetzt gelöst, in dem ich mich durch den gesamten Heap hangel und jeden Knoten einzeln lösche. Der ^-Operator scheint in der Tat wegen des records nicht nötig zu sein. Allerdings gab es noch eine kleine Gemeinheit. Wenn ich in meinem Turbo-Delphi eine Zeigervariable überwache, die ich mit dispose zerstöre, wird weiterhin deren alter Wert und Verknüpfungen angezeigt. Deshalb dachte ich die ganze Zeit, dass mein dispose nicht funktionieren würde :-)
Vielen Dank für eure Hilfe und Tips!
fiore
mkinzler - Do 10.09.09 15:51
Aber ich würde trotzdem dereferenzieren auch wenn der Compiler so nett ist und den falschen Code gnädig richtig interpretiert
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!