Autor Beitrag
Biergeneral
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 35

WIN XP
Delphi 7 Ent., Delphi 2007 Ent., C/C++ (Eclipse)
BeitragVerfasst: Sa 28.07.07 02:37 
Hallo =)

Bin bei einer nächtlichen Programmieraktion auf ein Phänomen gestoßen, wo ich mich jetzt Frage ob ich das richtig interpretiere.. Was zur folge hätte, dass ich einen ganzen Programmteil nochmal aufreißen müsste =)


Also ich hab folgendes gemacht.. :
Ich fuckel gerade mit ganz simplen OpenGl Sachen rum. Ich hab mir also Typen angelegt, die meine grafischen Objekte verwalten und auch zeichnen.
Diese Objekte haben jeweils 2 Listen. Zum einen eine Vertexliste, zum anderen eine Liste mit den Dreiecken.
Die Dreiecke verweisen dann auf die Vertexliste.
Gut, funktioniert soweit, die OpenGL Darstellung ist auch nicht das Problem bzw eigentlicher Inhalt meiner Frage =)


Beide Listen sind zur Zeit dyn. Arrays und sowohl der Vertex als auch der Dreieckstyp sind Records.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
type TVertex = record
  x,y,z: Single;
end;
type PVertex = ^TVertex;

type TTriangle = record
  V1,V2,V3 = PVertex;  // Eckpunkte
end;

type TVertexList = Array of TVertex;
type TTriangleList = Array of TTriangle;


Wenn ich jetzt ein neues Dreieck hinzufüge, weise ich den Eckpunkten ( V1, V2, V3 ) direkt die Pointer auf die Vertices zu. Also Adressen die sich in einem dynamischen Array befinden. ( In der Tat.. ein wenig hart :) )
ausblenden Delphi-Quelltext
1:
2:
3:
  TriangleListe[TriangleIndex].V1 :=@(VertexListe[VertexIndex]);
  TriangleListe[TriangleIndex].V2 :=@(VertexListe[VertexIndex]);
  TriangleListe[TriangleIndex].V3 :=@(VertexListe[VertexIndex]);


Anfürsich funktioniert das auch.. Aber habe jetzt weiter an meinem Programm rumgefuckelt.. Wenn ich jetzt noch andere Objekte nachträglich hinzufüge, spinnt die OpenGL-Anzeige. Beim nachforschen hat sich dann rausgestellt, dass die Werte in der TriangleListe nichtmehr stimmen.

Für mich sieht das danach aus, dass Delphi dynamische Arrays im Speicher hin und herschiebt, sobald ein Adressraum anders verwendet werden könnte.
Daher meine Fragen:

1. Stimmt diese Annahme? =) 2. Falls das so ist, kann man die Adressierung fixieren?

Sonst bleibt mir keine andere Wahl, als mit Objekten zu Arbeiten, was ich bisjetzt aus Geschwindigkeits und Speichergründen bei den Vertices nicht gemacht hab. :)

Gruß

Alle Rechtschreibfehler schieb ich auf die nächtlichen Wurstfinger ;)
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Sa 28.07.07 03:00 
So habe ich ehrlich gesagt noch nie ein dynamisches Array gefüllt. :? Warum greifst du nicht über die Indezes auf die Elemente des Arrays zu?
ausblenden Delphi-Quelltext
1:
2:
SetLength(MeinDynArray, 9);  // PLatz für 10 Elemente schaffen
MyDynArry[0] := Foobar; // dem ersten Element einen Wert zuweisen


Und was deine Frage angeht. Werden dynamische Arrays vergrößert, wird entsprechend Speicher alloziiert und der Inhalt des alten Arrays in das neue, größere Array kopiert. Dies geschieht aus dem Grund, weil alle Elemente eines dynamischen Arrays im Speicher hintereinander liegen müssen, um sie durch eine einfache Inkrementierung der Basisadresse des dynamischen Arrays adressieren zu können.
Biergeneral Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 35

WIN XP
Delphi 7 Ent., Delphi 2007 Ent., C/C++ (Eclipse)
BeitragVerfasst: Sa 28.07.07 03:36 
Ich füll das Array schon über die Indizes und nicht die Adressen.
Hab das vielleicht ein bischen merkwürdig formuliert, ist ja auch schon spät ;)

Die Arrays selbst behandel ich an für sich ganz "normal". Aber beide Listen sind jetzt miteinander verknüpft, da die Dreiecksliste auf die Werte aus der Vertexliste zugreift.
Außerdem teilen sich die Dreieck die gemeinsamen Eckpunkte.. Sprich mehrere Elemente in der Dreiecksliste zeigen auf ein Vertex.

Klar, ich könnte statt des Pointers auf das Vertex auch den Index im Array speichern, aber wenn ich dann auf die Werte zugreifen will, muss ich jedesmal einen Umweg gehen.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
// Statt meinem : 
  type TTriangle = record
    V1,V2,V3 : PVertex; // Pointer auf TVertex;
  end;
  
  Eckpunkt1 := TriangleList[Index].V1^;
  Eckpunkt2 := TriangleList[Index].V2^;
  Eckpunkt3 := TriangleList[Index].V3^;

// Hätte ich dann ja
  type TTriangle = record 
    V1,V2,V2 : Integer;  // Index des Vertex in der Vertexliste;
  end;
  
  Eckpunkt1 := VertexList[TriangleList[Index].V1];
  [...]


Sprich ich würd immer den Weg über beide Listen laufen, statt direkt zum Ziel zu kommen.


Zum anderen Teil.. Das sich die Adressierung ändert, sobald ich die größe des Arrays verändere ist mir bewusst, aber das tu ich ja garnicht.

Ich veränder an dem Array selbst garnichts, sondern füge an einer beliebigen anderen Stelle im Programm neue Objekte hinzu. Das geht bis zu nem bestimmten Zeitpunkt gut, aber dann ist die Adressierung im Eimer =)

Ich geh mal besser schlafen =)
Lossy eX
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1048
Erhaltene Danke: 4



BeitragVerfasst: Sa 28.07.07 07:12 
Also ich weiß nicht ob Delphi die auch noch mal anderweitig verschiebt aber wie Luckie schon sagte. Sobald das Array größer wird besteht die Möglichkeit, dass es nicht mehr an die aktuelle Speicherstelle passt und dann muss es verschoben werden. Und damit sind alle deine Pointer in der TriangleListe fürn Eimer.

Der Vorschlag mit den Indizes ist einer um das zu lösen und ich denke mal das wäre gar nicht so viel langsamer. Klar der muss dann 2 Arrayzugriffe machen aber das sind beides indizierte Zugriffe und damit ist das nicht so schlimm. Das würde ich auch gar nicht so stark optimieren wollen, weil es dafür reichlich andere Stellen gibt wo du versteckten Aufwand hast den du gar nicht vermuten würdest. ;)

Eine andere Möglichkeit wäre aber noch das Umstellen der VertexListe auf ein Array of PVertex;. Dann müsstest du aber beim Hinzufügen deiner Pointer die Vertices mittels GetMem erstellen und damit würde sich der Pointer außerhalb Delphis Einflussbereich befinden. Wenn jetzt das Array verändert würde dann würden zwar die Pointer kopiert werden aber deren Adresse würde sich nicht mehr ändern. Ist aber mehr Aufwand das zu verwalten. Und nicht zu vergessen du musst es selber wieder frei geben.

_________________
Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
Biergeneral Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 35

WIN XP
Delphi 7 Ent., Delphi 2007 Ent., C/C++ (Eclipse)
BeitragVerfasst: Sa 28.07.07 08:16 
Einen wunderschönen frühen Morgen...

Hab mir das nochmal ein wenig genauer angeschaut. Also der Adressbereich ändert sich defintiv, sobald in der Anwendung ein bestimmter Speicherverbrauch erzeugt wird.
Die Speicherverwaltung selbst zu übernehmen ist sicherlich eine Möglichkeit, aber vermutlich nicht die Beste =)

Ich werd mir mal durch den Kopf gehen lassen, wie man das noch lösen kann. Gibt ja zig Alternativen.
Mich hat ja eigentlich gewundert, dass Delphi das Array durch die Gegend schiebt. Bei Objekten wär ja undenkbar, dass sie einfach eine neue Adresse bekommen.
Aber ich hab auch mal irgendwann gelesen, dass man von Dereferenzierng und Referenzierung bei Arrays die Finger lassen sollte. Vermutlich war genau das der Grund ;)

Cheers
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Sa 28.07.07 09:25 
Bei normalen Pointern ist das genau das gleiche.

Wenn man für einen Pointer die Größe des Speicherbereiches ändert, auf den er zeigt, so muss sich die Speicherverwaltung umschauen (also entweder der interne von Delphi oder die von Windows), wo genug Platz verfügbar ist, um den neuen Speicherbereich unterzubringen. Wenn am aktuellen Standort nicht genug Platz ist, eben woanders.

Die einfachste Lösung für dein Problem wurde bereits oben von user profile iconLuckie gleich im ersten Post erwähnt: Nimm einfach die Indizes deines Vertex-Arrys als Zeiger. Damit kann sich die Adresse des Vertex-Arrays ändern, ohne dass Du davon etwas mitbekommst ODER darauf achten müsstest, da Delphi die Berechnungen der neuen Zeiger übernimmt.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Biergeneral Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 35

WIN XP
Delphi 7 Ent., Delphi 2007 Ent., C/C++ (Eclipse)
BeitragVerfasst: Sa 28.07.07 16:24 
Ja richtig, wenn ich den Speicherbereich eines Objektes selbst änderm, verändert sich der Pointer. Das war mir bekannt. Aber was ich nicht wusste ist, dass sich bei dynamischen Arrays der Addressbereich auch dann verändert, wenn andere Objekte in der Anwendung eine neue Größe bekommen. ( Also Objekte, die in keinem direkten Kontakt zu dem Array stehen )
Das war ja was mich verwundert hat =)