Um mal zuerst mit ein paar Missversändnissen aufzuräumen:
- Nein, ich bin nicht der Erfinder dieses Threads.
- Ich weiß, was arrays sind, dass man solche null- terminieren kann und warum man das macht
- ich glaube auch, dass die geeignetste Lösung die mit der Vorwärtsdeklaration ist
ABER:
Ich bin der Meinung, dass hier einige Verwirrung in punkto Zeiger im Umlauf sind. Daher habe ich (offensichtlich erfolglos) versucht, das entwas zu entwirren. Nicht mehr, nicht weniger.
Socke hat geschrieben:Ohne zu wissen, WAS du willst, kann dir auch niemand sagen WIE und WO du das richtig machst.
Braucht auch keiner, ich möchte gern, dass (auch) Du lernst, WIE und WO Du das richtig machst
Socke hat geschrieben:TMyNode ist ein Zeiger! Wenn du ihn irgendwo speichern willst, brauchst du natürlich ein Zeiger.
Stimmt so nicht. TMyNode ist eine Klasse. Eine Instanz dieser Klasse wird dynamisch alloziiert und sollte demnach einem Zeiger zugewiesen werden, wenn man kein Speicherleck verursachen will. Dieser Zeiger könnte auf dem Stack liegen (lokale Variable), auf dem heap (dynamische Variable) und im Datensegment (globale Variable). Beabsichtigt vom OP ist sicher das Ablegen auf dem Heap.
Socke hat geschrieben:Den Sinn eines Zeigers auf einen Zeiger habe ich aber immer noch nicht verstanden (siehe oben unter WAS). Die einzige Anwendung, die mir einfällt sind oben erwähnte Arrays oder Call-By-Reference (wenn man den Zeiger an sich bearbeiten will und nicht eine dahinter stehende Variable).
Im Speziellen: Es gibt keinen Grund für Zeiger auf Zeiger. Im Allgemeinen: Es gibt Gründe, manche Routine vereinfacht sich dadurch beispielsweise.
Aber wenn man Zeiger auf Zeiger benutzt, dann muss man es schlicht richtig machen, sonst fliegt einem alles um die Ohren.
Socke hat geschrieben:Syntaktisch ist das doch äquivalent zu meiner Variante, benötigt aber einen weiteren Typen. Außerdem war es nur als Beispiel gedacht, was für ’nen Müll im ersten Post dieses Threads steht.
Falls Du diese hier meinst
Syntaktisch korrekt ist sie schon, sagt ja auch der Compiler. Aber sie ist semantisch katastrophal.
Gehen wir doch mal durch:
Trees[x,y,z] ist eine (Member)Variable vom Typ ^TOctTree.
TOktTree.Create erzeugt erzeugt ein TOctTree (auch ein Zeiger, sieht man aber nicht mehr direkt). Durch das Create wird diesem Zeiger einem Stück Speicher zugewiesen (sagen wir mal 12345), wahrscheinlich auf dem Stack (also bei 54321)
Die Operation @ (Sockes Variante) ermittelt nun die Adresse dieses Stückchen Speichers, also die Adresse auf dem Stack (also 54321), die beim Beenden der Funktion mit irgendwelchen anderen Werten überschrieben wird.
Diese Adresse wird wird also an Trees[x,y,z] übergeben (da steht jetzt also 54321 drin)
Wenn ich jetzt Trees[x,y,z] anschaue, dann erhalte ich 54321, bei Trees[x,y,z]^ erhalte ich (solange der Stack noch so aussieht) korrekt 12345, also das tatsächlich zu diesem Zweck angelegte Objekt.
Verlasse ich die Funktion und der Stack wird überschrieben, dann steht in Trees[x,y,z] schon immer noch 54321 drin, dort hingegen steht mit großer Wahrscheinlichkeit NICHT mehr 12345, der Zeiger zeigt also ins Nirwana.
(Falls es jetzt klarer ist, bitte hier weiterlesen, ansonsten unten: Um das zu umgehen könnte ich erst einen PTOctTree-Zeiger auf dem Heap anlegen (Adresse 23456), diesem das Objekt zuweisen (12345) und diesen dann Trees[x,y,z] überhelfen (also 23456). Ich hätte dann also einen Zeiger auf den Heap auf eine Stelle, wo ein Zeiger steht, der auf mein Objekt zeigt)
Diese Variante ist entscheidend anders (wenn auch trotzdem ungünstig).
TOctTree erzeugt nach wie vor ein Objekt auf dem Heap (12345). Dieser Wert wird wahrscheinlich temporär irgendwo auf den Stack geschrieben (bei 54321). Mit dem Typecast bleibt die Adresse 12345, dem Compiler wird aber vorgegaukelt, dass es sich hierbei nicht um einen Zeiger auf ein Objekt handelt - so einen will er an dieser Stelle nämlich nicht haben - sondern, dass es sich um einen Zeiger auf einen Zeiger auf ein Objekt handelt. Es befindet sich also jetzt in Trees[x,y,z] ein Duplikat des Zeigers, der die Adresse 54321 hat und auf 12345 verweist. Wenn also der Stack wieder umgebaut ist, dann steht in Trees[x,y,z] immer noch 12345 drin, auch wenn der Compiler noch fälschlicherweise der Meinung ist, es handele sich um ein PTOcktTree.
Ich finde die laxe Handhabung von Zeigern in Delphi/FreePascal nicht besonders gut, weil tatsächlich viele nicht mehr wissen, was sie eigentlich tun. Aber es ist nun einmal so, und so bin ich auch bequem geworden und schreibe Trees[x,y,z].MeinFeld anstelle von Trees[x,y,z]^.MeinFeld ...