![]() |
noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
Moin @ALL,
hatte jetzt nochmal bissi zeit... und functions gefunden, die ne stringlist zurueckgeben. und laut test (siehe code) werden die auch nicht freigegeben (sagt jedenfalls "ReportMemoryLeaksOnShutdown") und ist ja auch irgendwie logisch. kann man sowas ueberhaupt irgendwie freigeben?? werde jetzt jedenfalls alles mal auf variante 2 umstellen. vllt. hat ja jemand nen kommentar uebrig... LG.. ..de Schorsch
Delphi-Quellcode:
function getSL: TStringList; overload; function getSL(var SL: TStringList): Boolean; overload; procedure TForm1.Button1Click(Sender: TObject); begin showmessage(getSL.Text); end; procedure TForm1.Button2Click(Sender: TObject); begin var sl := TStringList.Create; try getSL(sl); showmessage(sl.Text); finally FreeAndNil(sl); end; end; function TForm1.getSL: TStringList; begin result := TStringList.Create; result.Add('haha'); result.Add('hehe'); result.Add('hihi'); result.Add('hoho'); result.Add('huhu'); end; function TForm1.getSL(var SL: TStringList): Boolean; begin SL.Add('haha'); SL.Add('hehe'); SL.Add('hihi'); SL.Add('hoho'); SL.Add('huhu'); end; |
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
Du solltest aus dem var beim Parameter ein const machen, denn die Funktion soll die Referenz auf die Stringliste ja nicht ändern, sondern die Liste lediglich nutzen (füllen).
Wenn du dich um die Freigabe nicht kümmern möchtest, musst du Interfaces nutzen. Die musst du aber natürlich dann auch erst implementieren. Dann ginge auch Variante 1. |
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
Zitat:
Delphi-Quellcode:
Nicht empfohlene Lösung:
function CreateAndFillStringList: TStringList;
begin Result := TStringList.Create; Result.Add('...'); end; begin var sl: TStringList := CreateAndFillStringList; try sl.Add('more'); ShowMessage(sl.Text); finally sl.Free; end;
Delphi-Quellcode:
Bis bald...
uses
mormot.core.data; var sl: TStringList; begin with TAutoFree.One(sl, CreateAndFillStringList) do ShowMessage(sl.Text); end; Thomas |
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
Man gibt normalerweise mit Funktionen keine Objekte zurück, außer es sind die Getter eines anderen Objekts, das die Instanz des zurückgegebenen Objekts verwaltet (Beispiel: die diversen Lines von TMemo und Items von TComboBox). Oder irgendeine andere Klasse kümmert sich darum, dass die irgendwann freigegeben werden (z.B. TListItems.Add).
Nur Konstruktoren geben Objekte implizit zurück die nennt man auch so. Dann weiß man: Ich muss die so benutzen, wie du es bei Button2 gemacht hast. Im allergrößten Notfall macht man das wie mytbo geschrieben hat - aber auch hier heißt die Methode irgendwas mit "Create" und da weiß ich sofort, ich muss das Ding freigeben. Wie jaenicke schon sagte, sind übergibt man Klassen auch normalerweise nicht als var, da das Argument eigentlich nur der Zeiger ist und man die Felder und Eigenschaften von Klassen immer schreiben kann. In Delphi werden Klassen weder als var noch als const übergeben. Macht man im Normalfall bei Dingen, die ein Zeiger oder kleiner sind. Alternativ zu Interfaces kann man Records nutzen. Nachteil: Die haben keinen Destruktor, haben keine Vererbung und können sich nicht selbst referenzieren. |
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
Zitat:
Umgekehrt verwende ich es bei Interfaces teilweise nicht, wenn die Gefahr besteht, dass jemand als Parameter direkt einen Konstruktoraufruf verwendet, was mit der Referenzzählung Probleme machen kann. |
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
Zitat:
* Ja, die Vairable selbst wird nicht geändert, * aber der Inhalt schon. Zitat:
Delphi-Quellcode:
Was erstellt wird, muß auch wieder freigegeben werden, denn das "Objekt" macht es nicht von selbst.
procedure TForm1.Button1Click(Sender: TObject);
begin var Temp := getSL.Text; showmessage(Temp.Text); Temp.Fee; end; // aber eigentlich begin var Temp := getSL.Text; try showmessage(Temp.Text); finally Temp.Fee; end; end; ODER
Delphi-Quellcode:
* hier wird Extern nicht freigegeben
// FSL als Variable/Feld in der übergeordneten Klasse, also hier die TForm1
function TForm1.getSL: TStringList; begin if not Assigned(FSL) then FSL := TStringList.Create; // oder im OnCreate UND im OnDestroy sowieso das FSL.Free; FSL.Clear; FSL.Add('haha'); FSL.Add('hehe'); FSL.Add('hihi'); FSL.Add('hoho'); FSL.Add('huhu'); Result := FSL; end; * gleichzeitig, bzw. kurz nacheinander aufgerufen, muß man bedenken, dass das Result des vorherigen Aufrufs sich auch mit verändert (weil selbes Objekt) ODER z.B. irgendwas mit einem Interface ODER
Delphi-Quellcode:
function TForm1.getSL: TArray<string>;
ODER ... |
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
Zitat:
ABER: Mann sollte die Benamsung "Create...." nennen, damit man weiß, dass ein Objekte erzeugt wird, was extern freigegeben werden muß! :warn: |
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
Zitat:
Delphi-Quellcode:
funktioniert prima.
sl := FunctionDieEineStringlistErzeugt(bla, blub);
try Verarbeite(sl); finally sl.Free; end; Problematisch ist eher die erzeugende Function selbst, denn was, wenn nach dem Erzeugen der Stringlist eine Exception ausgelöst wird?
Delphi-Quellcode:
Und schwupps hat man ein Leak. Natürlich ist das nie so offensichtlich wie in diesem Beispiel.
function FunctionDieEineStringlistErzeugt(bla, blub: string): TStringList;
begin Result := TStringList.Create; Result.Add(bla); Result.Add(blub); raise Exception.Create('Test'); end; Meine Lösung dafür sieht so aus:
Delphi-Quellcode:
Ich bin mir allerdings sicher, dass das irgendwie eleganter gehen müsste.
function FunctionDieEineStringlistErzeugt(bla, blub: string): TStringList;
begin Result := TStringList.Create; try Result.Add(bla); Result.Add(blub); raise Exception.Create('Test'); except Result.Free; raise; end; end; Edit: Mir ist gerade noch eine Alternative eingefallen:
Delphi-Quellcode:
Ist aber auch nicht wirklich elegant.
function FunctionDieEineStringlistErzeugt(bla, blub: string): TStringList;
var sl: TStringList; begin sl := TStringList.Create; try sl.Add(bla); sl.Add(blub); raise Exception.Create('Test'); Result := sl; sl := nil; finally sl.Free; end; end; |
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
Zitat:
wenn dann sl auf nil gesetz wird, ist dann nicht auch result == nil? Grüße Klaus |
AW: noch was zu: "Nach 20/30 starts aus der IDE speicher voll"
Zitat:
Sowohl Result als auch sl sind Pointer auf das das Objekt. Wenn ich einen davon auf nil setze, hat das keinen Einfluss auf den anderen. Anders sähe das aus, wenn man sl nicht auf nil setzt:
Delphi-Quellcode:
Dann würde Result nach dem sl.Free auf ein freigegebenes Objekt zeigen und ein Zugriff hätte böse Folgen. Im Besten Fall eine Access Violation, im schlechtesten Fall würde zufälliger Code ausgeführt.
function FunctionDieEineStringlistErzeugt(bla, blub: string): TStringList;
var sl: TStringList; begin sl := TStringList.Create; try sl.Add(bla); sl.Add(blub); raise Exception.Create('Test'); Result := sl; // sl := nil; finally sl.Free; end; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:53 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