Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - ClassInterf. wird zu Pointer() as Interf. nach Memberaufruf
Symbroson - Mo 18.06.18 18:56
Titel: ClassInterf. wird zu Pointer() as Interf. nach Memberaufruf
Hallo EE und alles Gute nachträglich!, ich bins mal wieder. ;)
Wir sind (oder waren) in der Schule gerade bei 3D-Darstellug. Ich hab natürlich mein eigenes Ding gemacht und basierend auf meiner glm-Bibliothek alles zusammengebastelt.
Jetzt hatten wir die verschiedenen Darstellungsformen wie zB. Iso-, Di- oder Trimetrie. Diese Transformationen dürfen allerdings nicht das Objekt selbst ändern, sondern nur die Darstellung beeinflussen.
Also versuche ich mal im Code grob zu erklären, was ich gemacht habe:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45:
| type PTriaCon = ^TTriaCon; TTriaCon = record verts: array[0..2] of IVec4; color: integer; z: double; end;
TTria = class tria: PTriaCon; constructor Create(p1, p2, p3: IVec4; color: integer = 0); destructor Free; procedure transform(mat: IMat4x4); end;
TRect = class {$ifndef splitRects} trias: array[0..1] of TTria; verts: array[0..3] of IVec4; {$else} trias: array[0..3] of TTria; verts: array[0..4] of IVec4; {$endif} constructor Create(p1, p2, p3, p4: IVec4; color: integer = 0); destructor Free; procedure transform(mat: IMat4x4); end;
TCube = class rects: array[0..5] of TRect; {$ifndef splitRects} verts: array[0..7] of IVec4; {$else} verts: array[0..13] of IVec4; {$endif} constructor Create(p1, p2, p3, p4, p5, p6, p7, p8: IVec4); destructor Free; procedure transform(mat: IMat4x4); end;
var trias: array of PTriaCon; lverts: TStringList; tverts: array of IVec4; |
Bei den Klassen, speziell den
array of IVec4 nutze ich aus, dass diese nur Referenzen auf das Objekt speichern.
Der Grund, warum ich bei lverts eine TStringList verwendet habe ist, dass ich jeden Eckpunkt nur ein mal vertreten haben möchte und es by default keine Hashtables is Delphi7 gibt. Und ich hatte vorerst noch wenig lust mir selber ein Array zu basteln dass dann per Binärsuche und Insertsort Elemente findet und einfügt. Kommt vmtl noch.
So weit so gut. Jetzt zum Problem. Dieses tritt beim Rückkopieren der zwischengespeicherten Eckpunkte auf:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35:
| procedure DrawTriangles(bmp: TBitmap; matProj: IMat4x4); var i: integer; v0, v1, v2: IVec4; begin for i := 0 to HIGH(tverts) do begin tverts[i].assign(TVec4(lverts.Objects[i])); TVec4(lverts.Objects[i]).mul(matProj); end; SortTriangles(trias);
for i := 0 to HIGH(trias) do begin v0 := trias[i].verts[0]; v1 := trias[i].verts[1]; v2 := trias[i].verts[2]; bmp.Canvas.Brush.Color := trias[i].color; bmp.Canvas.Polygon([ Point(calcx(v0.x), calcy(v0.y)), Point(calcx(v1.x), calcy(v1.y)), Point(calcx(v2.x), calcy(v2.y)) ]); end;
for i := 0 to HIGH(tverts) do begin TVec4(lverts.Objects[i]).assign(tverts[i]); end; end; |
Jetzt passiert folgendes beim Rückkopieren: bei
i = 8 (was dem 2. Eckpunkt des Würfels entspricht) wird aus dem IVec4 des Würfels ein Pointer. Alle anderen bleiben IVec4, nur der verliert anscheinend seine Gültigkeit.
Hier einige Screens:
Vor dem Rückkopieren:
Vor der fraglichen Zuweisung:
nach der Zuweisung:
Die TVec4.assign-Methode kopiert übrigens nur die Koordinaten ins andere Objekt, mehr nicht. Das kann also kaum die Ursache sein:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| function TVec4.assign(v: TVec4) : TVec4; begin result := assign(v.x, v.y, v.z, v.w); end; function TVec4.assign(v: IVec4) : TVec4; begin result := assign(v.x, v.y, v.z, v.w); end; function TVec4.assign(x, y, z, w: double): TVec4; begin fx := x; fy := y; fz := z; fw := w; result := self; end; |
Kann sich das jemand erklären, warum ausgerechnet dieses Objekt verschwindet? Ich bin echt ratlos. Vielleicht hat es etwas mit der Verwendung von TStringList und der Konvertierung zu TObject zu tun, das erklärt aber nicht den Einzelfall.
Vielen dank im Vorraus :)
jaenicke - Mo 18.06.18 23:05
Benutzt du dort die Referenzzählung bei der Benutzung von IVec4? Dann ist es keine gute Idee parallel mit Objektreferenzen auf TVec4 zu arbeiten. Entweder nur Interfaces (würde ich empfehlen) oder nur Objektreferenzen, dann klappt es auch mit der Referenzzählung.
Konkret sehe ich auf Anhieb auch keine direkte Ursache, aber es muss denke ich mit der Referenzzählung zu tun haben.
Symbroson - Mo 18.06.18 23:14
Also wenn du meinst, dass ich den Referenzenzähler selber beeinflusse dann nein. Ich erstelle lediglich die Objekte und weise die dem Array zu, sodass alle Plätze im Array initialisiert wurden. Später nutze ich wie gesagt nur assign, dass nur die Koordinaten übernimmt.
Ich schau mal wie die Zähler sich verhalten…
Symbroson - Mo 18.06.18 23:36
Erwies sich als schwierig - ich kann das zu TVec4 gecastete Object nicht zu IVec4 casten. :nixweiss:
Ich schicke aber nochmal die Funktion rein, in der die Liste initialisiert wird - vielleicht bringt uns das weiter:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35:
| constructor TTria.Create(p1, p2, p3: IVec4; color: integer = 0); var len: integer; begin inherited Create; new(tria); tria.color := color; tria.verts[0] := p1; tria.verts[1] := p2; tria.verts[2] := p3;
lverts.AddObject(Format('%p', [pointer(p1)]), TObject(p1)); lverts.AddObject(Format('%p', [pointer(p2)]), TObject(p2)); lverts.AddObject(Format('%p', [pointer(p3)]), TObject(p3)); len := LENGTH(tverts); setLength(tverts, lverts.Count); while len < lverts.count do begin tverts[len] := Vec4(0); inc(len); end; len := length(trias); SetLength(trias, len + 1); trias[len] := tria; end; |
Symbroson - Mi 20.06.18 14:38
Ich hab jetzt lverts doch mal als array of IVec4 implementiert - und da scheint es keine Probleme zu geben.
Merkwürdig :gruebel:
jaenicke - Mi 20.06.18 21:55
Weil du dort nur mit den Interfaces arbeitest und nicht mit Objektreferenzen. Dadurch bleibt die Referenz in der Liste aktiv.
Referenzzählung ist ja im Grunde erst einmal sehr einfach. Wenn du einer Interfacereferenz eine Instanz zuweist, wird darin der Referenzzähler um 1 inkrementiert. Entfernst du die wieder, wird er wieder dekrementiert.
Nehmen wir mal diesen Quelltext, nur als Beispiel:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| var p1: IVec4; begin p1 := TVec4.Create; lverts.AddObject(Format('%p', [pointer(p1)]), TObject(p1)); end; |
Nach der Zuweisung an p1 ist der Referenzzähler auf 1. Dann packst du die Referenz als Objekt in die Liste. Am Ende der Methode geht p1 aus dem Scope und wird daher wieder abgeräumt. Der Referenzzähler geht auf 0 und somit wird das Objekt wieder freigegeben. Die Referenz in der Liste ist somit ungültig.
Machst du das gleiche mit deinem Array, geht der Referenzzähler stattdessen auf 2 hoch und beim Abräumen der Variable wieder auf 1 herunter. Das Objekt wird also nicht freigegeben.
Symbroson - Mi 20.06.18 22:08
Ok das macht Sinn. Seltsam bleibt nur, dass nur ein einziges Interface betroffen war.
Danke auf jeden Fall für deine Hilfe! :)
jaenicke - Do 21.06.18 09:59
Symbroson hat folgendes geschrieben : |
Seltsam bleibt nur, dass nur ein einziges Interface betroffen war. |
Durch die Freigabe des Objekts wird noch kein Speicher überschrieben, er wird nur wieder als frei markiert. Deshalb merkt man das Problem oft erst später, wenn der Speicher an der Stelle, an der das Objekt lag, anderweitig verwendet wurde und daher dort keine gültigen Daten mehr liegen.
Anders sieht das aus, wenn du FastMM einbindest. Das überschreibt die Daten bei der Freigabe mit einem speziellen Muster, so dass es direkt beim Zugriff immer knallt und dies auch erkannt wird.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2024 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!