Pointer Zuweisungen - Umweg notwendig

Für Fehler in Lazarus, um diese von anderen verifizieren zu lassen.
carli
Beiträge: 657
Registriert: Sa 9. Jan 2010, 17:32
OS, Lazarus, FPC: Linux 2.6.x, SVN-Lazarus, FPC 2.4.0-2
CPU-Target: 64Bit

Re: Pointer Zuweisungen - Umweg notwendig

Beitrag von carli »

Arrgh, da stehn mir ja die Haare zu Berge.

Hier die Musterlösung:

Code: Alles auswählen

TOctTree = class;
 
  TOctTreeNode = class
     Trees: array [0..1,0..1,0..1] of TOctTree;
     procedure Start;
  end;
 
  TOctTree = class
    //... unimportant informations...
    node:TOctTreeNode; // if node = nil then last OctTree
  end;
 
procedure TOctTreeNode.Start;
var
   x,y,z:integer;
   puf:TOctTree;
begin
for x := 0 to 1 do
    begin
    for y := 0 to 1 do
        begin
        for z := 0 to 1 do
            begin
            puf := TOctTree.Create;
            Trees[x,y,z] := puf;
            end;
        end;
    end;
end;


Ich nehme mal an, du wolltest ein C++-Tutorial übernehmen. In C++ sind "Klassen" aber nichts anderes als TurboPascal-Objekte, also records mit Methoden. In FPC hingegen ist "class" ein Zeiger auf [...], um den man sich keine weiteren Sorgen machen muss.

am2
Lazarusforum e. V.
Beiträge: 116
Registriert: Di 21. Dez 2010, 09:59
OS, Lazarus, FPC: Win (L 0.9.26 beta FPC 2.2.2)
CPU-Target: 32 Bit

Re: Pointer Zuweisungen - Umweg notwendig

Beitrag von am2 »

Socke hat geschrieben:Dein ursprüngliches Problem könnte syntaktisch korrekt so aussehen:

Code: Alles auswählen

Trees[x,y,z] := @TOctTree(TOctTree.Create);

Das weiß ich nicht. Es ist mir tatsächlich nicht klar, ob @ dann die Adresse eines Zeigers auf das Objekt oder den Methodenzeiger auf den Konstruktor zurückliefert. Aber angenommen, er lieferte tatsächlich die Adresse eines Zeigers auf das Objekt, dann wäre das wahrscheinlich ein temporäres Stückchen Speicher auf dem Stack, mit dem Du eigentlich nichts anfangen darfst. Semantisch korrekt wäre weiterhin ein

Code: Alles auswählen

Trees[x,y,z] := New(PTOctTree); Trees[x,y,z]^:=TOctTree.Create;


Socke hat geschrieben:
am2 hat geschrieben:... einiges (offensichtlich Misslungenes) zur Veranschaulichung ...

Soll das heißen, die Deklaration

heißt, dass TOctTreeNode.Trees[x,y,z] als array of TOctTree interpretiert werden soll?

Nö, da hast Du mich mißverstanden. es ist und bleibt ein Array von Zeigern auf Zeiger auf einen Knoten.

Socke hat geschrieben:Dann fehlt noch die Null-Terminierung. Einfacher wäre wohl

Code: Alles auswählen

Node: array[0..1,0..1,0..1] of array of TOctTree;


am2 hat geschrieben:Und jetzt zu dieser Konstruktion
TOktNode=class
Node=array of PTOktNode
...

Node enthält ein Array von Zeigern auf Zeiger, nicht auf Objekte des Typs TOktNode. Wenn ich also das System nicht vergewaltigen will, dann müßte ich einen Zeiger auf dem Heap alloziieren, der dann seinerseits auf ein Objekt vom Typ TOktNode zeigt. Das ist mit Kanonen auf Spatzen geschossen, zugegeben, wäre aber der korrekte weg bei dieser Definition.

Wenn dieses TOktNode.Node sich also wie ein PPChar nur eben mit TOktNode anstatt Char verhalten soll, würde ich die Pascal-Variante Node: array of array of TOktNode vorschlagen.
Mir ist immer noch nicht ganz klar, was du mit einem Zeiger auf eine Klasse erreichen willst.

Ich weiß nicht, welches Array Du terminieren willst. Das Array des Beispiels diente nur der Schilderung des Sachverhaltes. Ich persönlich will gar nichts erreichen, ich versuche nur zu erklären, was da eigentlich abläuft. Es ist kein Problem des "WAS", sondern des "WO".
Wenn ABC ein Zeiger vom Typ PTOctTree ist, dann kann (sollte) er eben nicht direkt auf ein TOctTree verweisen, sondern nur auf einen Zeiger dorthin. Und für diesen Zeiger muß irgendwo - wenn dynamisch, dann auf dem Heap - ein Platz zur Verfügung stehen und damit geschaffen werden. Um Dein Beispiel von oben noch einmal aufzugreifen:

Code: Alles auswählen

Trees[x,y,z] := @TOctTree(TOctTree.Create);

Möglich wäre

Code: Alles auswählen

Trees[x,y,z] := PTOctTree(TOctTree.Create);
als expliziter Typecast. Trees wäre dann zwar der Meinung, dass es Zeiger auf Zeiger enthält, was aber nicht den Tatsachen entspräche. Das wäre syntaktisch korrekt, käme ohne Speicherleaks aus - ist aber hinsichtlich der Zeiger schlicht eine Vergewaltigung, die dann auch von Anfang bis Ende so durchgezogen werden müßte, also TypeCast bei jedem Zugriff und Beachtung auch beim Freiräumen des Speichers.

Die m.E. korrekte Umsetzung bleibt die schon vorgeschlagene

Code: Alles auswählen

//PTOctTree = ^TOctTree; //unnötig, stattdessen
  TOctTree = class; //Forwarddeklaration
 
  TOctTreeNode = class
     Trees: array [0..1,0..1,0..1] of TOctTree;
//                                    ^^^^^^^^^
     procedure Start;
  end;
 
  TOctTree = class
    //... unimportant informations...
    node:TOctTreeNode; // if node = nil then last OctTree
  end;

carli
Beiträge: 657
Registriert: Sa 9. Jan 2010, 17:32
OS, Lazarus, FPC: Linux 2.6.x, SVN-Lazarus, FPC 2.4.0-2
CPU-Target: 64Bit

Re: Pointer Zuweisungen - Umweg notwendig

Beitrag von carli »

@am2: Wieso zitierst du falschen Code? Es gibt Leute, die copy&pasten bloß den Quelltext, ohne die Texte dazwischen zu lesen. Für solche Leute ist das extrem tödlich fürs Verständnis des Stoffs.

am2
Lazarusforum e. V.
Beiträge: 116
Registriert: Di 21. Dez 2010, 09:59
OS, Lazarus, FPC: Win (L 0.9.26 beta FPC 2.2.2)
CPU-Target: 32 Bit

Re: Pointer Zuweisungen - Umweg notwendig

Beitrag von am2 »

carli hat geschrieben:@am2: Wieso zitierst du falschen Code? Es gibt Leute, die copy&pasten bloß den Quelltext, ohne die Texte dazwischen zu lesen. Für solche Leute ist das extrem tödlich fürs Verständnis des Stoffs.

Ich weiß nicht, aber ich denke, wer bei mehreren Code- Beispielen in einem Post willkürlich eines auswählt, ohne den umgebenden Post zu lesen, der hat sowieso ein grundsätzliches Problem. Ich denke, um die Unterschiede zu erkennen, sollte man beides nebeneinander sehen können. Aber das ist sicher Geschmackssache. Mir kommt es eben darauf an, dass begriffen wird, was ich meine, und nicht, dass der Codeschnipsel zwingend allen Anforderungen des Posters entspricht. Wenn ich Code veröffentlichen will, der funktioniert, dann wäre das sicher mindestens funktionsweise, wenn nicht gar modulweise.

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Pointer Zuweisungen - Umweg notwendig

Beitrag von Socke »

am2 hat geschrieben:Ich weiß nicht, welches Array Du terminieren willst. Das Array des Beispiels diente nur der Schilderung des Sachverhaltes. Ich persönlich will gar nichts erreichen, ich versuche nur zu erklären, was da eigentlich abläuft. Es ist kein Problem des "WAS", sondern des "WO".

Zeigerarrays kann man in C wunderbar null-terminieren. Dann kennt man zum einen die Länge und kann sich zum anderen noch eine weitere Variable für diese sparen.
Ohne zu wissen, WAS du willst, kann dir auch niemand sagen WIE und WO du das richtig machst.

am hat geschrieben:Nö, da hast Du mich mißverstanden. es ist und bleibt ein Array von Zeigern auf Zeiger auf einen Knoten.

Zerlegen wir das mal von hinten:

Code: Alles auswählen

// Knoten
TMyNode = class(TObject);
// Zeiger auf Knoten
TMyNode
// array von Zeigern auf Zeiger auf Knoten
array of TMyNode

TMyNode ist ein Zeiger! Wenn du ihn irgendwo speichern willst, brauchst du natürlich ein Zeiger. 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).
am2 hat geschrieben:Wenn ABC ein Zeiger vom Typ PTOctTree ist, dann kann (sollte) er eben nicht direkt auf ein TOctTree verweisen, sondern nur auf einen Zeiger dorthin. Und für diesen Zeiger muß irgendwo - wenn dynamisch, dann auf dem Heap - ein Platz zur Verfügung stehen und damit geschaffen werden. Um Dein Beispiel von oben noch einmal aufzugreifen:

Daher verstehe ich auch nicht, warum du einen Zeiger auf TOctTree speichern willst. TOctTree ist bereits ein Zeiger.
am2 hat geschrieben:Möglich wäre

Code: Alles auswählen

Trees[x,y,z] := PTOctTree(TOctTree.Create);
als expliziter Typecast. Trees wäre dann zwar der Meinung, dass es Zeiger auf Zeiger enthält, was aber nicht den Tatsachen entspräche. Das wäre syntaktisch korrekt, käme ohne Speicherleaks aus - ist aber hinsichtlich der Zeiger schlicht eine Vergewaltigung, die dann auch von Anfang bis Ende so durchgezogen werden müßte, also TypeCast bei jedem Zugriff und Beachtung auch beim Freiräumen des Speichers.

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.

am hat geschrieben:Die m.E. korrekte Umsetzung bleibt die schon vorgeschlagene

Was verschiedene Leute schon versucht haben zu erklären... Aber schön, dass wir endlich hier angekommen sind.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

am2
Lazarusforum e. V.
Beiträge: 116
Registriert: Di 21. Dez 2010, 09:59
OS, Lazarus, FPC: Win (L 0.9.26 beta FPC 2.2.2)
CPU-Target: 32 Bit

Re: Pointer Zuweisungen - Umweg notwendig

Beitrag von am2 »

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:
am hat geschrieben:

Code: Alles auswählen

Trees[x,y,z] := PTOctTree(TOctTree.Create);


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
Socke hat geschrieben:

Code: Alles auswählen

Trees[x,y,z] := @TOctTree(TOctTree.Create);



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)

Code: Alles auswählen

Trees[x,y,z] := PTOctTree(TOctTree.Create);

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 ...

carli
Beiträge: 657
Registriert: Sa 9. Jan 2010, 17:32
OS, Lazarus, FPC: Linux 2.6.x, SVN-Lazarus, FPC 2.4.0-2
CPU-Target: 64Bit

Re: Pointer Zuweisungen - Umweg notwendig

Beitrag von carli »

am2:
Instanzen von Klassen kommen immer auf den Heap, nie auf den Stack.

Und auch das Casten von TTyp auf PTyp, wenn man eigentlich einen TTyp speichern will, mag zwar funktionieren, aber es drückt nicht das aus, was es soll.

Auch die Handhabung, wann Zeiger verwendet werden und wann nicht, ist vom FPC extrem streng gehandelt:
- . bedeutet bei records der direkte Zugriff auf den Speicher
- ^. bedeutet bei P-records der Zugriff auf den Speicher
- Objekte (Instanzen von class) sind immer Zeiger und werden immer mit . angesprochen
- @ gibt die Speicheradresse an, an der die Daten stecken (bei Prozeduren der Einsprungpunkt [@@ ist dann der Zeiger auf den Einsprungpunkt-Zeiger])

marcov
Beiträge: 1100
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: Pointer Zuweisungen - Umweg notwendig

Beitrag von marcov »

am2 hat geschrieben:
Socke hat geschrieben:Dein ursprüngliches Problem könnte syntaktisch korrekt so aussehen:

Code: Alles auswählen

Trees[x,y,z] := @TOctTree(TOctTree.Create);

Das weiß ich nicht. Es ist mir tatsächlich nicht klar, ob @ dann die Adresse eines Zeigers auf das Objekt oder den Methodenzeiger auf den Konstruktor zurückliefert.


Und wie mann davon die Adresse bekommt? Ein Expression hat nicht automatisch eine Adresse.

Aber angenommen, er lieferte tatsächlich die Adresse eines Zeigers auf das Objekt, dann wäre das wahrscheinlich ein temporäres Stückchen Speicher auf dem Stack, mit dem Du eigentlich nichts anfangen darfst. Semantisch korrekt wäre weiterhin ein

Code: Alles auswählen

Trees[x,y,z] := New(PTOctTree); Trees[x,y,z]^:=TOctTree.Create;



Ich habe die erste paar Beitrage von dir gesehen, und ich denke die sein völlig Korrekt. De Post wo obere Code zum ersten mal stand inklusive.
Ich verstehe auch nicht ganz was Socke meint. Meint er das deine Code falsch ist, oder nur das der OP etwas anders will?

marcov
Beiträge: 1100
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: Pointer Zuweisungen - Umweg notwendig

Beitrag von marcov »

carli hat geschrieben:am2:
Instanzen von Klassen kommen immer auf den Heap, nie auf den Stack.


Normalerweise ja.

Es kann schon (ungetested, aus Erinnerung)

Code: Alles auswählen

procedure yy;
var x : array[0..100] of char;
      p : TMyClass;
begin
   p:=TMyClass(@x[0]);
   p.initinstance;
   p.Create;

am2
Lazarusforum e. V.
Beiträge: 116
Registriert: Di 21. Dez 2010, 09:59
OS, Lazarus, FPC: Win (L 0.9.26 beta FPC 2.2.2)
CPU-Target: 32 Bit

Re: Pointer Zuweisungen - Umweg notwendig

Beitrag von am2 »

carli hat geschrieben:am2:
Instanzen von Klassen kommen immer auf den Heap, nie auf den Stack.

Habe nichts anderes behauptet. Aber der Zeiger darauf, der kann und wird temporär mit Sicherheit auf dem Stack liegen.
carli hat geschrieben:Und auch das Casten von TTyp auf PTyp, wenn man eigentlich einen TTyp speichern will, mag zwar funktionieren, aber es drückt nicht das aus, was es soll.

Ganz meiner Meinung.

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Pointer Zuweisungen - Umweg notwendig

Beitrag von Socke »

am2 hat geschrieben:
carli hat geschrieben:am2:
Instanzen von Klassen kommen immer auf den Heap, nie auf den Stack.

Habe nichts anderes behauptet. Aber der Zeiger darauf, der kann und wird temporär mit Sicherheit auf dem Stack liegen.
carli hat geschrieben:Und auch das Casten von TTyp auf PTyp, wenn man eigentlich einen TTyp speichern will, mag zwar funktionieren, aber es drückt nicht das aus, was es soll.

Ganz meiner Meinung.

Könnten wir den Thread dann nicht damit schließen, dass wir alle wissen, was wir meinen nur aneinander vorbeireden?

marcov hat geschrieben:
am2 hat geschrieben:
Socke hat geschrieben:Dein ursprüngliches Problem könnte syntaktisch korrekt so aussehen:

Code: Alles auswählen

Trees[x,y,z] := @TOctTree(TOctTree.Create);

Das weiß ich nicht. Es ist mir tatsächlich nicht klar, ob @ dann die Adresse eines Zeigers auf das Objekt oder den Methodenzeiger auf den Konstruktor zurückliefert.


Und wie mann davon die Adresse bekommt? Ein Expression hat nicht automatisch eine Adresse.

Ich wollte nur den Code aus dem ersten Post syntaktisch korrigieren. In meinem Code ist aber ein Denkfehler: Ein Konstruktor ist keine Funktion und hat kein Ergebnis(-typ). Daher kann man auch keinen Adresse dessen ermitteln. Ich weiß nicht, was genau passiert, aber

Code: Alles auswählen

o := TObject.Create();
ist nicht also äquivalent zu einem Funktionsaufruf.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

MAC
Beiträge: 770
Registriert: Sa 21. Feb 2009, 13:46
OS, Lazarus, FPC: Windows 7 (L 1.3 Built 43666 FPC 2.6.2)
CPU-Target: 32Bit

Re: Pointer Zuweisungen - Umweg notwendig

Beitrag von MAC »

Bevor wir uns hier alle noch die Köpfe einschlagen möchte ich mich lieber nochmal wiederholen und Erwähnen. Das folgender Code verwendet wird.

Code: Alles auswählen

TOctTree = class;
 
  TOctTreeNode = class
     Trees: array [0..1,0..1,0..1] of TOctTree;
     procedure Start;
  end;
 
  TOctTree = class
    //... unimportant informations...
    node:TOctTreeNode; // if node = nil then last OctTree
  end;


Den Teil der Diskussion, den ich nachvollziehen kann (ich bin nicht sonderlich schlau :) ) find ich aufjedenfall interessant.

Code: Alles auswählen

Signatur := nil;

am2
Lazarusforum e. V.
Beiträge: 116
Registriert: Di 21. Dez 2010, 09:59
OS, Lazarus, FPC: Win (L 0.9.26 beta FPC 2.2.2)
CPU-Target: 32 Bit

Re: Pointer Zuweisungen - Umweg notwendig

Beitrag von am2 »

MAC hat geschrieben:Bevor wir uns hier alle noch die Köpfe einschlagen möchte ich mich lieber nochmal wiederholen und Erwähnen. Das folgender Code verwendet wird.

Code: Alles auswählen

TOctTree = class;
 
  TOctTreeNode = class
     Trees: array [0..1,0..1,0..1] of TOctTree;
     procedure Start;
  end;
 
  TOctTree = class
    //... unimportant informations...
    node:TOctTreeNode; // if node = nil then last OctTree
  end;


Den Teil der Diskussion, den ich nachvollziehen kann (ich bin nicht sonderlich schlau :) ) find ich aufjedenfall interessant.

Das freut mich. Aber eine Frage hätte ich doch noch. Warum machst Du es nicht klassisch, also

Code: Alles auswählen

TOctTree = class;
 
  TOctTreeNode = class
     ChildNodes: array [0..1,0..1,0..1] of TOctNode;
//                                         ^^^^^^^^
     procedure Start;
  end;
 
  TOctTree = class
    //... unimportant informations...
    RootNode:TOctTreeNode; // if node = nil then last OctTree
  end;


So, wie Du es gebaut hast, hast Du immer

Tree -> Node -> array of Trees -> node -> array of Trees ....
in der Standardvariante wäre es
Tree -> Node -> array of nodes -> array of nodes ...

Inhaltlich klappt beides, aber gibt es einen Grund für das Zwischenschieben von Bäumen?

MAC
Beiträge: 770
Registriert: Sa 21. Feb 2009, 13:46
OS, Lazarus, FPC: Windows 7 (L 1.3 Built 43666 FPC 2.6.2)
CPU-Target: 32Bit

Re: Pointer Zuweisungen - Umweg notwendig

Beitrag von MAC »

Trees sind die Würfel, oder Container. Und jeder dieser Container hängt an einem Node und hat ein Node für andere Container.
Würd ich jetzt die Container weglassen. Hätte ich wie du meinst viele viele Nodes.
Nur das es so geplant war das die Container die wichtigen sachen lösen und die Nodes als Hilfsgerüst dienen :) Und deshalb wird es schwer diese Wegzulassen ...

Code: Alles auswählen

Signatur := nil;

am2
Lazarusforum e. V.
Beiträge: 116
Registriert: Di 21. Dez 2010, 09:59
OS, Lazarus, FPC: Win (L 0.9.26 beta FPC 2.2.2)
CPU-Target: 32 Bit

Re: Pointer Zuweisungen - Umweg notwendig

Beitrag von am2 »

MAC hat geschrieben:Trees sind die Würfel, oder Container. Und jeder dieser Container hängt an einem Node und hat ein Node für andere Container.
Würd ich jetzt die Container weglassen. Hätte ich wie du meinst viele viele Nodes.
Nur das es so geplant war das die Container die wichtigen sachen lösen und die Nodes als Hilfsgerüst dienen :) Und deshalb wird es schwer diese Wegzulassen ...


Auf den ersten Blick nicht.

Das heißt, der Baum (bzw. Container) enthält viel Intelligenz und ein bisschen Link auf weitere Container

Dann würde auch

TOctTree=class
ChildTrees=array ... of TOctTree;
procedure EineVonVielenWichtigenProceduren;
...
end;

funktionieren (ist ja de facto das gleiche). Also, wenn der Zusammenhang zwischen Node und Tree immer 1:1 ist und nur die zwischen Tree und node 1:8, dann brauchst Du m.E. wirklich bloß eine Struktur. Um das mal zu verdeutlichen:

Im Moment
Tree -> 8 Nodes -> je Node 1 Tree -> je Tree 8 Nodes -> je Node 1 Tree -> je Tree 8 Nodes ...
Wenn Du nun "Tree -> je Tree 8 Nodes" zusammenfasst zu "TMySpecialTree", dann hast Du
MySpecialTree -> 8 MySpecialTrees -> je MySpecialTree 8 MySpecialTrees
usw.

Ein Ausschlusskriterium könnte natürlich sein, dass es sich nicht ursprüngliche Trees und Nodes handelt, sondern verschiedene Erben ins Spiel kommen, wie

Tree: TTreePapa -> je 8 Node:TNodeOpa -> je 1 Tree:TTreeTochter -> je 8 Node:TNodeEnkel -> je 1 Tree:TTreeMutter

also in diesem Fall wäre es zu aufwändig. Aber anderenfalls müßtest Du das Knotenarray eigentlich auch als Member des Trees (TMySpecialTree) auffassen und implementieren können.

Antworten