![]() |
TObjectList sauber an function übergeben und wieder zurück
Hallo.
ich habe eine TObjectList, bei der ich verschiedene Berechnungen vornehmen will. Ich suche den sauberen Weg, wie ich die Liste an die Funktionen übergeben und des Ergebnis wieder zurück gebe. Dabei soll es möglich sein, dass die SourceList unverändert bleibt. Hier ein abgespecktes Beispiel
Delphi-Quellcode:
So das Prinzip.
type
TTest = class private FValue: Double; public property Value: Double read FValue write FValue; constructor Create; destructor Destroy; override; end; TTestList = class(TObjectList<TTest>); implementation procedure PrePareList(SourceList, DestList: TTestList); // Erstellt Liste und kopiert Werte von SourceList dort hin var i: Integer; lTest: TTest; begin if DestList <> nil then DestList.Free; DestList := TTestList.Create(true); for i := 0 to SourceList.Count - 1 do begin lTest := TTest.Create; DestList.Add(lTest); lTest.Value := SourceList[i].Value; end; end; function DoAdding(SourceList, DestList: TTestList):Boolean; var i: Integer; lTempList: TTestList; begin PrePareList(SourceList, DestList: TTestList); // Damit wird in jedem Fall DestList = SourceList zurück gegeben for i := 0 to DestList.Count - 1 do DestList[i].Value := DestList[i].Value + 5; Result := true; // Wenn korrekt ausgeführt. In Beispiel einfach immer end; function DoMultiplicate(SourceList, DestList: TTestList):Boolean; var i: Integer; lTempList: TTestList; begin PrePareList(SourceList, DestList: TTestList); // Damit wird in jedem Fall DestList = SourceList zurück gegeben for i := 0 to DestList.Count - 1 do DestList[i].Value := DestList[i].Value * 5; Result := true; // Wenn korrekt ausgeführt. In Beispiel einfach immer end; procedure DoCalculations(SourceList, DestList: TTestList); var lTempList: TTestList; begin PrePareList(SourceList, DestList: TTestList); // Damit wird in jedem Fall DestList = SourceList zurück gegeben if FlagAddieren then begin if DoAdding(DestList, lTempList: TTestList) then begin DestList.Free; DestList := lTempList; lTempList := nil; end; end; if FlagMultiplicate then begin if DoMultiplicate(DestList, lTempList: TTestList) then begin DestList.Free; DestList := lTempList; lTempList := nil; end; // Bei false wären Daten ja immer noch unverändert in DestList. Abder ein mögliches Speicherleck end; end; procedure Start; var i: Integer; lStartList, lResultList: TTestList; lTest: TTest; begin lStartList := TTestList.Create(true); try for i := 1 to 5 do begin lTest := TTest.Create; lStartList.Add(lTest); lTest.Value := i; end; DoCalculations(lStartList, lResultList: TTestList); finally lStartList.Free; lResultList.Free; end; end; Jetzt aber die Fragen:
|
AW: TObjectList sauber an function übergeben und wieder zurück
Antwort zu Punkt 3: den „var“-Parameter kannst du dir sparen, Objekte werden immer über Call-By-Reference (also quasi var) übergeben.
|
AW: TObjectList sauber an function übergeben und wieder zurück
Zitat:
Beispiel:
Delphi-Quellcode:
Diese Konstruktion produziert ein Memoryleak, weil DestList durch den Aufrufer nicht freigegeben werden kann. Denn die Referenz der neu erzeugten Liste wird so nicht an den Aufrufer zurückgegeben. Richtig ist folgende Konstruktion:
procedure PrePareList(SourceList, DestList: TTestList);
// Erstellt Liste und kopiert Werte von SourceList dort hin var i: Integer; lTest: TTest; begin DestList.Free; DestList := TTestList.Create(true); for i := 0 to SourceList.Count - 1 do begin lTest := TTest.Create; DestList.Add(lTest); lTest.Value := SourceList[i].Value; end; end;
Delphi-Quellcode:
So muss das dann komplett durchgezogen werden. Also:
procedure PrePareList(SourceList: TTestList; var DestList: TTestList);
// Erstellt Liste und kopiert Werte von SourceList dort hin var i: Integer; lTest: TTest; begin DestList.Free; DestList := TTestList.Create(true); // <- diese Referenz muss zurück gegeben werden for i := 0 to SourceList.Count - 1 do begin lTest := TTest.Create; DestList.Add(lTest); lTest.Value := SourceList[i].Value; end; end;
Delphi-Quellcode:
function DoAdding(SourceList: TTestList; var DestList: TTestList): Boolean;
function DoMultiplicate(SourceList: TTestList; var DestList: TTestList):Boolean; |
AW: TObjectList sauber an function übergeben und wieder zurück
Das stimmt so nicht. Das Objekt (genauer: die Instanz) selbst wird ohne Angabe von const, var oder out als Call by Value übergeben. Wenn man ein Objekt als Konstantenparameter übergibt, kann man ihm keine andere Instanz zuweisen, aber seine Eigenschaften ändern. Ich würde aber in Routinen ohne triftigen Grund keine Instanzen erzeugen, da man sonst sehr schnell durcheinanderkommt und sich entweder Speicherlecks oder wilde Zeiger fabriziert. Stattdessen bevorzuge ich persönlich folgende Vorgehensweise:
Delphi-Quellcode:
[edit] Mist, zu langsam [/edit]
procedure TuWas(const Src, Dest: TSomeList);
var i: integer; begin Assert(Assigned(Src), 'Keine Quellliste übergeben'); Assert(Assigned(Dest), 'Keine Zielliste übergeben'); Dest.Clear; for i := 0 to Src.Count - 1 do begin // Nur als Beispiel Dest.Add(Src[i]); end; end; |
AW: TObjectList sauber an function übergeben und wieder zurück
Zunächst Danke für die schnellen Antworten
Zitat:
Um es sicher zu stellen:
Zitat:
Zitat:
Zitat:
Letzte Frage: Könnte Aufbau
Delphi-Quellcode:
Vorteile bieten? Was muss da beachtet werden bzw. stimmt das hier?
lTempList := DoAdding(DestList)
Delphi-Quellcode:
function PrePareList(SourceList: TTestList): TTestList;
// ------------------------------------------------------------------------------------------ // Erstellt Liste und kopiert Werte von SourceList dort hin var i: Integer; lTest: TTest; begin Result.Clear; for i := 0 to SourceList.Count - 1 do begin lTest := TTest.Create; Result.Add(lTest); lTest.Value := SourceList[i].Value; end; end; function DoAddition(SourceList: TTestList): TTestList; // ------------------------------------------------------------------------------------------ // Führe rechenfunktion durch, die auch auf vorige Werte in der Liste zurückgreift. // Wenn SourceList und Result auf selbem Objekt liegen, wurden die vorigen Werte durch den Loop schon verändert => Zuerst zusätzliche Instanz schaffen. Oder gibt es andere Möglichkeit? var i: Integer; lTest: TTest; lTempList:TTestList; begin lTempList := lTempList.Create(true); lTempList := PrePareList(SourceList); for i := 0 to SourceList.Count - 1 do begin if i>0 then Result.Value := lTempList[i].Value + lTempList[i-1].Value else Result.Value := lTempList[i].Value; end; lTempList.Free; end; Procedure Start; // ------------------------------------------------------------------------------------------ // Vorbereitung der Liste und Aufruf der Funktionen var lStartList, lResultList:TTestList; begin lStartList := TTestList.Create(true); lResultList := TTestList.Create(true); ... lResultList := PrePareList(SourceList); // Und hier mein Problem. Da die Berechnungen aufeinander aufbauen sollen, ist Result-Objekt = Übergabe-Objekt. Wenn jeder Eintrag für sich geändert wird kein Problem. // Wenn die Funktion aber auf vorige Einträge zugreift, wären die schon verändert. Jetzt müsste ich in der Funktion zuerst eine Kopie erzeugen. Korrekt? lResultList := DoAddition(lResultList); ... lStartList.Free; lResultList := TTestList.Create(true); |
AW: TObjectList sauber an function übergeben und wieder zurück
Wo soll das Funktionsergebnis (also die Instanz) denn herkommen, wenn sie nicht innerhalb der Funktion erzeugt wird? Was spricht denn dagegen, beide Instanzen in der aufrufenden Routine zu erzeugen und als Konstanten-Parameter zu übergeben?
|
AW: TObjectList sauber an function übergeben und wieder zurück
Zitat:
Doch ein kleines Problem habe ich doch. Wie muss das dann aussehen?
Delphi-Quellcode:
procedure TuAlles(const SourList, DestList:TTestList);
begin TuWas1(SourceList, DestList); // Wie gehe ich vor, dass mit dem nächsten Aufruf die vorige DestList als SourceList übergeben wird TuWas2(SourceList, DestList); end; // Das hier funktioniert nicht mehr, da ja als const hereingegeben und damit die Zuweisung DestList := lTempList; fehl schlägt procedure TuAlles(const SourList, DestList:TTestList); var lTempList:TTestList; begin PrepareDestList(SourceList, DestList); lTempList:=TTestList.Create; PrepareDestList(SourceList, lTempList); if TuWas1(DestList, lTempList)then begin DestList.Free; // Jetzt muss ich die ja freigeben um danach meine neue Ergebnisse dran zu hängen DestList := lTempList; lTempList:= nil; end; lTempList:=TTestList.Create; PrepareDestList(SourceList, lTempList); if TuWas2(DestList, lTempList)then begin DestList.Free; DestList := lTempList; lTempList:= nil; end; end; |
AW: TObjectList sauber an function übergeben und wieder zurück
Ich würde ohne Grund nicht an den Instanzen herumspielen, sondern nur an den enthaltenen Daten.
Delphi-Quellcode:
procedure Tuwas(sonst Src, Dest: TSomeList);
begin // Mit den Daten der Listen arbeiten end; procedure TuAlles; var List1: TSomeList; List2: TSomeList; List3: TSomeList; begin List3 := nil; List2 := nil; List1 := TSomeList.Create; try List2 := TSomeList.Create; TuWas(List1, List2); List3 := TSomeList.Create; TuWas(List2, List3); finally List1.Free; List2.Free; List3.Free; end; end; |
AW: TObjectList sauber an function übergeben und wieder zurück
In der Art hatte ich es ursprünglich. Da die Berechnungen zum Teil aufwändig sind, führe ich sie nur noch aus, wenn sie auch benötigt wird
Delphi-Quellcode:
was so dann natürlich nicht geht. Wenn TuWas1 nicht ausgeführt würde müsste ich List1 statt List2 in TuWas2 eingeben
if FlagTuWas1 then
TuWas1(List1, List2); if FlagTuWas2 then TuWas2(List2, List3); Und der Ansatz
Delphi-Quellcode:
erscheint mir aufwändig, da das neue Ergbnis immer wieder in lTempList kopiert wird um es dann wieder dem nächsten Aufruf übergeben zu können
var
lTempList:TTempList; begin PrepareDestList(SourceList, DestList); lTempList:= TAbsBaseList.Create(true); try // ------------------------------------------------------------------------------------------------------------------------------------- if FlagTuWas1 then if TuWas1(DestList, lTempList) then // Wenn erfolgreich ausgeführt PrepareDestList(lTempList, DestList); // Ergebnis in Weitergabe-/Rückgabeliste kopieren // ------------------------------------------------------------------------------------------------------------------------------------- if FlagTuWas2 then if TuWas2(DestList, lTempList) then PrepareDestList(lTempList, DestList); // Ergebnis in Weitergabe-/Rückgabeliste kopieren finally lTempList.Free; end; end; |
AW: TObjectList sauber an function übergeben und wieder zurück
Benötigst Du denn wirklich mehrere Instanzen? Was genau hast Du eigentlich vor?
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:03 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 by Thomas Breitkreuz