![]() |
Records, Pointer, Listen & Co.
Hallo Zusammen,
da ich schon seit ein paar Jahren nicht mehr mit sowas gearbeitet habe, wollt ich einfach noch mal hier nachfragen. Also ich möchte in meinem Projekt ein unbestimmte Anzahl an Informatismengen dynamisch speichern. Jede dieser Informationsmengen besteht aus einem tPoint und vier boolchen Werten, weshalb sich hier ja ein Record anbieten würde. Die einzelnen Mengen sind auch liniear mit einander verbunden, weshalb ich sie per pointer zu einer einseitigen Liste verketten könnte. Was ich nun nicht mehr ganz weiß ist: Muss ich ich, wenn ich die Informationsmengen "verwerfen" möchte, mich auch konkret selber um die "Entsorgung" kümmern, indem ich sie z.B. auf NIL setze, oder passiert das automatisch im Hintergrund?! Oder gibt es vielleicht noch einen wesentlich unkomplizierteren Weg (z.B. mit Hilfe von tList) um mein Vorhaben zu realisieren? würde mich über ein Paar Tips sehr freuen, grüße, Evian |
Re: Records, Pointer, Listen & Co.
Sers,
ein Weg der vielleicht etwas umständlich ist, aber ganz gut geht ist folgender: du definierst das was du als record definieren woltest als klasse ( zb. TMyData ) und definierst den TPoint und die 4 bools als felder der klasse. jetzt kannst du eine TObjectList anlegen. dann erzeugst du deine TMyData klassen und fügst sie der ObjectList hinzu. der trick dabei ist einen Wert der TobjectList, der sich OwnsObject oder so ähnlich nennt , auf true zu setzen, weil dann die objectlist beim löschen einzelner items oder vernichten der gesamten liste die vorher hinzugefügten object freigibt. wie gesagt. evtl. ist das ein overkill aber es funktioniert. Gruß tn249 |
Re: Records, Pointer, Listen & Co.
Zitat:
Und zum ersten Beitrag: Setzt Du Pointer auf nil, dann hast Du noch nicht den Speicherbereich auf den die Pointer vorher gezeigt haben frei gegeben. Aber arbeite einfach nicht explizit mit Pointern - Delphi macht das ja implizit sobald Du eine Klasse definierst. Frei geben kannst Du Klasseninstanzen indem Du deren Free-Methode aufrufst. Dabei musst Du aufpassen, dass Du nichts doppelt frei gibst. Hast Du beispielsweise das von tn249 erwähnte OwnsObjects-Feld auf True gesetzt, dann gibt die Liste alle Elemente frei, sobald sie selbst frei gegeben wird. D.h. du darfst diese nicht vorher selbst frei geben. |
Re: Records, Pointer, Listen & Co.
Hi Leute,
das mit dem nil funzt nur, wenn man ein dynamisches Array anlegt. Hier kann man sicher folgendes machen:
Delphi-Quellcode:
Das sieht sicher recht einfach aus. Ich persönich habe aber fest gestellt, dass man immer wieder zusätzliche Methoden für den Zugriff auf die einzelnen Elemente in der Liste benötigt.
type
TMyData = Record Point : TPoint; Param1 : Boolean; Param2 : Boolean; Param3 : Boolean; Param4 : Boolean; end; type TDataList = array of TMyData; type TForm1 = class(TForm) private { Private-Deklarationen } FDataList : TDataList; public { Public-Deklarationen } procedure AddData(Data : TMyData); procedure Clear; end; var Form1: TForm1; implementation {$R *.DFM} { TForm1 } procedure TForm1.AddData(Data: TMyData); begin IF High(FDataList) = 0 then SetLength(FDataList, 1) else SetLength(FDataList, Length(FDataList) + 1); FDataList[High(FDataList)] := Data; end; procedure TForm1.Clear; begin FDataList := nil; end; Dann kommt man von selbst auf das was bttb930 sagt. Ich benutze übrigens nur noch diese Methode. Der Vorteil ist unter anderem, dass du häufig benötigte Functionen in dein Listenobject integrieren kannst und nebenbei natürlich schon ne Menge Funktionalität vor findest. Ein kleines Bsp. hier:
Delphi-Quellcode:
o.k. ich hab mir hier jetzt das creieren und frei geben der Liste gespart, aber es soll nur mal die grundlegende Vorgehensweise zeigen. Wie in den vorherigen Beiträgen beschrieben wird jetzt mit der Freigabe der Liste automatisch auch jedes enthaltene Data-Objekt mit frei gegeben.
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, contnrs; type TMyData = class(TObject) private FParam1: Boolean; FParam4: Boolean; FParam2: Boolean; FParam3: Boolean; FPoint: TPoint; protected public Constructor Create(APoint : TPoint; Param1, Param2, Param3, Param4 : Boolean); overload; property Point : TPoint read FPoint write FPoint; property Param1 : Boolean read FParam1 write FParam1; property Param2 : Boolean read FParam2 write FParam2; property Param3 : Boolean read FParam3 write FParam3; property Param4 : Boolean read FParam4 write FParam4; end; type TDataList = class(TObjectList) private protected public Function GetPointfromIndex(Index : Integer):TPoint; end; type TForm1 = class(TForm) private { Private-Deklarationen } FDataList : TDataList; public { Public-Deklarationen } procedure AddData(Data : TMyData); end; var Form1: TForm1; implementation {$R *.DFM} { TForm1 } procedure TForm1.AddData(Data: TMyData); begin IF not Assigned(FDataList) then Exit; FdataList.Add(Data); end; { TMyData } constructor TMyData.Create(APoint: TPoint; Param1, Param2, Param3, Param4: Boolean); begin inherited create; FParam1 := Param1; FParam2 := Param2; FParam3 := Param3; FParam4 := Param4; FPoint := APoint; end; { TDataList } function TDataList.GetPointfromIndex(Index: Integer): TPoint; var Data : TMyData; begin // vorbelegen Result := Point(-1, -1); // bei blödsinnigem Index raus IF (Index < 0) or (Index >= self.Count) then Exit; // Typ-casting Data := TMyData(self.Items[Index]); try IF not assigned(Data) then Exit; Result := Data.Point; except Result := Point(-1, -1); end; end; das wars von mir, Gruß oki |
Re: Records, Pointer, Listen & Co.
Ich mache es ein klein wenig anders als oki:
bei mir ist TDataList NICHT von TObjectList abgeleitet sondern ANTHÄLT eine TObjectList:
Delphi-Quellcode:
Nachteil: Ich muss alle Funktionen die ich aus der ObjectList brauche nochmal schreiben (Clear usw), die Inhalte sind aber kurz da sie ja nur die entsprechenden FList-Funktionen aufrufen (FList.Clear usw).
type
TDataList = class private FList: TObjectList; function GetCount: Integer; // gibt FList.Count zurück function GetItem(Index: Integer): TMyData; // gibt FList[i] as TMyData zurück ... public constructor Create; // erstellt die Liste mit FList := TObjectList.Create(True{AOwnsObjects}); destructor Destroy; // löscht die Liste mit FList.Free; procedure Clear; // ruft FList.Clear auf property Count: Integer read GetCount; property Items[Index: Integer]: TMyData read GetItem; ... end; Vorteil: Der Benutzer dieser Klasse (das kann ja ein ganz anderer Programmierer sein) kann in diese Liste nur die von mir gewünschten Objekte einfügen, also beispielsweise nur TMyData. Andere Klassen werden - anders als beim Ableiten von TObjectList - nicht angenommen. Dafür entfällt dann der Typecast (bei oki die Zeile Data := TMyData(self.Items[Index]); die besser Data := Items[Index] as TMyData wäre aber nun Data := Items[Index] sein muss). Wie oki das macht hab ich's früher auch gemacht, aber die Erfahrung lehrt mich, dass das zu fehlerträchtig und zuwenig flexibel ist. Ich will auch gar nicht alle public-Funktionen von TObjectList anbieten, sondern nur einen Teil, den ich dann teilweise auch verändern möchte. |
Re: Records, Pointer, Listen & Co.
Hi,
grundsätzlich gebe ich bttb930 recht. Bis jetzt war mir das dann aber doch zu viel Aufwand. Dazu muß ich sagen, dass ich in der Regel alleine arbeite und selten jemand meine Classen benutzen muß. Vielleicht sollte man mal schauen, ob man dann nicht doch die paar methoden von TObjectList überschreibt. Dass könnte dann durchaus so aussehen:
Delphi-Quellcode:
Das ist dann so ala TObjectList aus TList. Alle weiteren Methoden die spezielle Relevanz haben müßten dann natürlich auch überschrieben werden.
type
TMyList = class(TObjectList) private protected public function Add(AObject: TMyData): Integer; end; { TMyList } function TMyList.Add(AObject: TMyData): Integer; begin Result := inherited Add(AObject); end; Ich will jetzt nicht den Eindruck erwecken unbedingt eine andere Methode als bttb930 nach Vorne zu bringen. Bis heute überschreibe ich auch keine Methoden von TObjectList (warum eigentlich nicht :gruebel: ). dieser Weg viel mir gerade so ein, und ich find ihn gar nicht so schlecht. Gruß oki |
Re: Records, Pointer, Listen & Co.
Das Überschreiben ist in diesem Fall aber gefährlich, da die Methode Add NICHT als virtual deklariert ist. Das heißt Du kannst in Deinem Beispiel per Liste.Add(...) zwar nur TMyDatas in die Liste eintragen, per (Liste as TObjectList).Add(...) aber beliebige TObjects. Und das passiert schneller als man denkt, nicht unbedingt durch expliziten TypeCast aber etwa wenn Du eine andere Prozedur hast, die als Parameter eine TObjectList erwartet. Der könntest Du Deine TMyList übergeben (ist ja eine TObjectList), wenn diese Prozedur aber Add aufruft, dann eben nicht TMyList.Add sondern TObjectList.Add.
|
Re: Records, Pointer, Listen & Co.
hui, da ist ja doch einiges Zusammen gekommen. Werd nachher erstmal die Vorschlag von Oki umsetzen und sofern es noch irgendwelche Probleme gibt, werd ich mich noch mal melden.
Aber vielen Danke erstmal, für die ausführlichen Beschreibungen. |
Re: Records, Pointer, Listen & Co.
Hi,
um es gleich klar zu stellen; bttb hat Recht! Gut, und nun mein Aber: Zitat:
Das muß man sich so vorstellen, dass ich eine Liste der Personen auch TPersonenListe nenne. Ich selber gehe davon aus, dass jemand in einen Behälter nur das gibt, was da rein gehört. Wer in den Kühlschrank die Wäsche legt, hat selber schuld. Da ich aber auch versuche möglichst DAU-sicher zu proggen gebe ich im Grunde bttb recht. In wie Weit mein Vorschlag zum Überschreiben Konventionssicher ist, weis ich auch nicht. Gruß oki |
Re: Records, Pointer, Listen & Co.
naja, mit DAUs hat das nicht viel zu tun, aber wenn ich alleine programmiere bin ich auch gerne mal faul.
nur programmiere ich idR im team mit 5-10 anderen entwicklern - und da rächen sich faulheiten früher oder später immer. egal ob DAUs im team sind oder nicht. grundsätzlich überschreibt man nicht-virtuelle funktionen und prozeduren nicht. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:35 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz