Registriert: Sa Jul 22, 2006 00:43 Beiträge: 30 Wohnort: Borland
Hi
Ich habe vor diverse Elemente per verketteten Listen anzulegen um so flexibel zu sein und alle Elemente eines Typs auf einmal ansprechen zu können, egal wieviele es gerade sind.
Leider habe ich nicht ganz so viel Erfahrung damit und weiß gerade nicht warum ich einen Fehler bekomme.
Habe den Code mal auf das nötigste für mein Problem reduziert:
In Zeile 80 bekomme ich dann eine Zugriffsverletzung wenn ich die Textur dem neuen Objekt zuweisen möchte, allerdings weist er die Werte der paar letzten Zeilen (76-79) normal zu.
//Prozedur um alle Schiffe auf dem Spielfeld zu zeichnen
//Durchgehen aller Elemente in der verketteten Liste
procedure TForm1.DrawShips;
begin
//Ist ein Objekt vorhanden?
if(pStart<>nil)thenbegin
if(pStart=pEnde)thenbegin
//Nur ein Element
pStart.draw;
endelsebegin
//Beim ersten Element anfangen
pAktuell:=pStart;
repeat
pAktuell.draw;
pAktuell:=pAktuell.pNaechster;
until(pAktuell<>pEnde);
end;
end;
end;
Weiß jemand von euch Rat? Was mache ich falsch? Wenns ein Problem mit dem Pointer ist müsste es ja auch in Zeile 76-79 eine Zugriffsverletzung geben oder übersehe ich da was?
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Das Wichtigste vorweg. Klassen sind bereits Pointer. Da verkettete Liste meistens aber mit Record gemacht werden braucht man dort einen zusätzlichen Pointertypen. Du brauchst so aber keinen.
Und da du Klassen als Einträge benutzt kannst du auch nicht New benutzen. Klassen immer über den Konstruktor erstellen..
Also würde der Code in etwa so aussehen.
Code:
var
pStart : TShip =Nil;//erstes Element in der Liste
pAktuell : TShip =Nil;//aktuelles Element in der Liste
procedure TForm1.Button8Click(Sender:TObject);
begin
//Testweise ein neues Schiff in die verkettete liste einfügen
//Element anlegen
pAktuell := TShip.Create;
pAktuell.Rotate:=360;
pAktuell.PosVect[0]:=300;
//erstes Element anlegen
if((pStart=nil)AND(pEnde=nil))thenbegin
pStart:=pAktuell;
Ich denke wenn du deinen Code komplett darauf umgetstellt hast sollte es funktionieren. Denke ich. Ob die Pointer richtig gesetzt werden darauf habe ich jetzt nicht geachtet.
2 Hinweise noch am Rande. Verkettete Listen lohnen sich nur wenn du Einträge schnell umhängen musst, den Ersten löschen musst etc. Wenn du sagen wir mal 200 Schiffe hast von denen evtl mal eines gelöscht wird etc, dann kannst du auch locker eine Liste benutzen. Denn wenn du auf Element 50 zugreifen möchtest musst du so immer erst mal die Liste durchsuchen und das dauert mitunter länger als das simple Speicher umkopieren bei einer TList. Unter anderem erleichtert das den Code auch nicht immer.
Bei Pointern solltest du grundsätzlich IMMER dereferenzieren. Delphi macht es zwar weitestgehend automatisch aber ich habe es schon mal erlebt, dass er es in gewissen Situationen nicht getan hat. Deswegen immer PointerVariable^.blah := .... Und alleine auch schon weil man den Code so einfacher verstehen kann. Auch du selber wenn du in 2 Monaten den mal wieder siehst.
Registriert: Sa Jul 22, 2006 00:43 Beiträge: 30 Wohnort: Borland
Hi, vielen Dank für deine Antwort
Wieder was dazu gelernt. Wichtig war mir eben, dass ich für OpenGL alle Objekte der Klasse auf einmal ansprechen/zeichnen kann und, dass das Einfügen und Entfernen nicht an irgendwelche Arrays (auch nicht dynamische) gebunden ist, da die Anzahl der Objekte offen sein soll. Wie genau würde das bei einer TList aussehen? Ich habe die noch nicht benutzt.
Frage nebenbei: Wie oben geschrieben habe ich auch nach einer Möglichkeit gesucht eine Methode der Klasse für alle existierenden Objekte der Klasse ausführen zu lassen, wie könnte ich sowas machen ohne Arrays oder Listen? Gibt es da auch eine Möglichkeit?
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Zitat:
und, dass das Einfügen und Entfernen nicht an irgendwelche Arrays (auch nicht dynamische) gebunden ist, da die Anzahl der Objekte offen sein soll.
Folgendes musst du mir mal bitte erklären. Denn für mich sieht es so aus als ob du ziemlich genau weißt warum du es so nicht machen möchtest? Bzw würde mich mal interessieren was du unter Offen verstehst. Also welche Maximalanzahl dir da durch den Kopf geht.
Eine TList ist eine Klasse die ein dynamisches Array kappselt. Also intern benutzt es auch nur ein dynamisches Array. Und du erstellst davon ein Instanz. Kannst bequem Einträge hinzufügen, löschen etc und dir zurück geben lassen.
Code:
var
List: TList;
begin
List := TList.Create;
List.Add(Ship);
List.Add(Ship);
List.Add(Ship);
List.Add(Ship);
for Idx :=0to List.Count-1do
TShip(List[Idx]).Draw;
List.Free;
end;
Das mal als kleines Beispiel. Wenn du sehr viele Einträge hast und die Einträge einzeln löschen möchtest bietet es sich an die Liste von Hinten zu löschen. Da ansonsten die Einträge jedes mal verschoben werden müssen. Das ist außer an zeitkritischen Stellen oder bei gigantischen Eintragszahlen aber auch nicht so tragisch und dadurch, dass der Speicher direkt kopiert wird ist es auch nicht allzu langsam.
Zitat:
Wie oben geschrieben habe ich auch nach einer Möglichkeit gesucht eine Methode der Klasse für alle existierenden Objekte der Klasse ausführen zu lassen, wie könnte ich sowas machen ohne Arrays oder Listen? Gibt es da auch eine Möglichkeit?
Ich muss gestehen, dass ich nicht ganz weiß was du möchtest. Ist das so etwas wie ich habe 200 Instanzen von TShip erstellt und möchte nun von allen 200 eine Methode aufrufen? Wenn ja dann geht das nur in du alle 200 irgendwo registrierst. Zum Beispiel in einer Liste (egal welche Form). Und anschließend musst du durch die Liste und die Methode aufrufen.
Registriert: Sa Jul 22, 2006 00:43 Beiträge: 30 Wohnort: Borland
Im Grunde genommen möchte ich zur Zeit zum testen garkein Limit, sprich so viel wie der Speicher verkraftet Um mal zu testen wie hoch man das je nach Rechner treiben kann. Aber wenn ich irgendeine Zahl sagen soll wirds schwierig, da ich noch nicht genau abschätzen kann wieviele es später werden. Könnte mir vorstellen, dass es sicher mehrere hundert werden oder sogar mehr.
Ich dachte es wäre wirklich schneller ohne Arrays aber das mit der TList war mir so noch nicht bekannt. Ich denke ich werde das mal testen.
Zitat:
Ich muss gestehen, dass ich nicht ganz weiß was du möchtest. Ist das so etwas wie ich habe 200 Instanzen von TShip erstellt und möchte nun von allen 200 eine Methode aufrufen? Wenn ja dann geht das nur in du alle 200 irgendwo registrierst. Zum Beispiel in einer Liste (egal welche Form). Und anschließend musst du durch die Liste und die Methode aufrufen.
Exakt, schließlich muss ja jedes Schiff gezeichnet werden und diese Routine habe ich in eine Methode der Schiffsklasse gepackt.
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Zitat:
Exakt, schließlich muss ja jedes Schiff gezeichnet werden und diese Routine habe ich in eine Methode der Schiffsklasse gepackt.
Da wirst du um eine Iterative Lösung nicht drumherum kommen.
Zitat:
dass es sicher mehrere hundert werden oder sogar mehr.
Also ich denke es würde erst ab einer 5 stelligen Anzahl wirklich spannend werden. Wobei es sehr stark darauf ankommt was du tust. Wenn du sehr häufig vom Anfang Einträge löschen musst könnte eine verkettete Liste wesentlich besser sein. Da bei einer TList muss wie gesagt immer der Speicher kopiert werden, da die Daten immer an einem Stück liegen. Allerdings beim Häufigen erstellen und Freigeben dürften Klassen auch nicht so gut sein. Da dann der Speichermanager von Delphi sehr viel zu tun bekommt.
Allerdings sage ich jetzt einfach mal so, dass bei allem unter 1000 es so gut wie kaum einen markanten Unterschied geben wird. Selbst wenn die Daten häufiger mal kopiert werden müssen.
Bei großen Datenmengen kommt es immer sehr stark darauf an was du tust und damit machen willst. Teilweise fähr man besser wenn man mehr Speicher verbraucht. Teilweise ist die eine Lösung zwar schnell wenn man Einträge einfügen will allerdings beim Durchsuchen wieder langsam. Oder beim Einfügen langsam und dafür beim Durchsuchen schnell. Das hängt halt grundsätzlich immer daran was du tun willst.
Wenn die Reihenfolge keine Rolle spielt, kann man auch in einer nicht verketteten Liste effizient löschen, indem man das zu löschende Element mit dem letzten vertauscht und dann das letzte Element löscht.
Zusätzlich kann man noch bei jedem Element (TShip) seinen Index in der Liste speichern. Dann geschieht das Löschen auch in konstanter Zeit.
Anstelle der TList wäre vielleicht die TObjectList interessant. Diese Liste gibt den Speicher der Objekte automatisch frei, wenn sie aus der Liste entfernt werden oder die TObjectList gelöscht wird.
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Öhm. Ich habe zwar nicht ganz verstanden was du da genau wissen willst. Aber ja. Du kannst die Objekte auch direkt per Add hinzufügen. Also wie in deinem Code.
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Ich benutze meist solche Konstrukte:
Code:
with TShip(List.Items[List.Add(TShip.Create({evlt parameter}))])do
begin
//...
end;
Oder gebe eben den Wert zurück. TList.Add gibt ja praktischerweise den Index des hinzugefügten Items zurück.
Gruß Lord Horazont
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Ich muss gestehen, dass sich mir bei solchen Konstrukten die Fußnägel hochrollen.
Also wenn man einen Wert doppelt braucht dann bevorzuge ich eine lokale Variable. Zu mal es auch übersichtlicher ist. Und solche vielfältige Verschachtelung versuche ich immer zu vermeiden.
Mitglieder in diesem Forum: 0 Mitglieder und 14 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.