![]() |
Funktionsrückgabe freigeben
Hallo.
Es geht um Funktionen, die für die Rückgabe einen Datentyp besitzen, der innerhalb der Funktionen ersteinmal erstellt werden muss. Als Beispiel soll folgender Code dienen, den ich in einem älteren Posting fand:
Delphi-Quellcode:
Ich habe zum Testen nun simpel und einfach eine Zuweisung vorgenommen, die auch tadellos funktioniert:
function GetFileIcon(AFileName: string; AIndex: integer = 0): TIcon;
begin Result := TIcon.Create; Result.Handle := ExtractIcon(HInstance, PCHAR(AFileName), AIndex); end;
Delphi-Quellcode:
Startet man nun den Taskmanager, so kann man schön beobachten, wie der Speicherbedarf dieser Testanwendung steigt, wenn man vielfach auf den Button klickt.
procedure TForm1.Button1Click(Sender: TObject);
begin // Icon aus Exe auslesen und Image zuweisen Image1.Picture.Graphic := GetFileIcon('C:\Windows\NotePad.exe'); end; Nun betrachte ich stattdessen eine Prozedur als Lösung, bei der ich im ButtonClick eine TIcon-Variable anlege, erstelle und der Prozedur als Var-Parameter übergebe. Kehrt der Ablauf nach der Prozedur in das ButtonClick zurück, erfolgt die Zuweisung an Image1.Picture.Graphic. Danach gebe ich diese TIcon-Variable im ButtonClick frei. Hierbei ist im Taskmanager beim Klicken auf den Button kein Zuwachs an Speicherbedarf zu erkennen. Fazit: Offensichtlich werden die Speicherresourcen nicht freigegeben, die von der Funktionen mit TIcon als Datentyp belegt wurden. Frage: Wie kann man den belegten Speicher einer Funktionen, wie sie in obigen Beispiel zu sehen ist, wieder freigeben? Guido. |
Re: Funktionsrückgabe freigeben
Hallo,
probier mal
Delphi-Quellcode:
Icon:= GetFileIcon('C:\Windows\NotePad.exe');
Image1.Picture.Graphic.Assign(Icon); Icon.Free; Heiko |
Re: Funktionsrückgabe freigeben
Hi,
das hat mit Funktion bzw. Prozecuren direkt doch nichts zu tun. Du schreibst doch selbst Zitat:
|
Re: Funktionsrückgabe freigeben
Zunächst mal danke für eure Antworten.
Zitat:
Wie gesagt, probiert habe ich selbst schon (auch diese Möglichkeit). An Lösungen bin ich interessiert. Denn hierbei wird lediglich der Speicher für "Icon" freigegeben, NICHT der von der Funktion belegte! Dann hätte ich gerne gewust, wie ihr Postings lest!? Jetzt habe ich mich doch wirklich bemüht, das Problem möglichst verständlich zu beschreiben. Und um zu unterscheiden was gemeint ist, habe ich Prozedur und Funktion farblich hervorgehoben! Zitat:
Guido. |
Re: Funktionsrückgabe freigeben
Indem man keine Funktionen nimmt die da drin ein Objekt erstellen. Sowas ist totaler Müll, Prozeduren mit var Parmatern sollte man benutzen.
Hat man dennoch mal das Problem (und zwar wenn man scheisse Programmiert hat) dann geht das so:
Delphi-Quellcode:
Das was du da schreibst (mit Assign) is eigentlich so richtig gemacht, weiß nicht was du da noch freigeben willst ausser
Icon := IrgendNefuntionDieNenIconZurückgibt;
// ... was mit icon amchen Icon.Free; Bitmap.Assign(nil) vill |
Re: Funktionsrückgabe freigeben
Und um noch brechis Aussage zu ergänzen: Es ist dann sehr hilfreich (finde ich), wenn diese Funktion im Namen irgendetwas von "create" mit drin hat. Das hilft bei der Fehlersuche :mrgreen:
@brechi, sollte man die Variable nicht mit const übergeben? |
Re: Funktionsrückgabe freigeben
Moin Zusammen,
um das Ganze mal zu verallgemeinern:
Delphi-Quellcode:
Es ginge statt der Prozedur natürlich auch eine Funktion, solange diese kein Objekt zurückliefert.
// Das const soll verhindern, dass man sich den Pointer auf das Objekt zerschiesst
procedure IchMacheWasMitIrgendeinemObjekt(const AObjekt : TIrgendeineKlasse); begin //... end; var ObjektVariable : TIrgendeineKlasse; begin ObjektVariable := TIrgendeinKlasse.Create; try IchMacheWasMitIrgendeinemObjekt(ObjektVariable); finally FreeAndNil(ObjektVariable); // oder ObjektVariable.Free; end; end; |
Re: Funktionsrückgabe freigeben
Kleine Zwischenfrage:
Welche Unit brauche ich, um ExtractIcon(HInstance, PCHAR(AFileName), AIndex) benutzen zu können? :gruebel: Danke. |
Re: Funktionsrückgabe freigeben
Windows?
|
Re: Funktionsrückgabe freigeben
Ich verwende immer sowas:
Delphi-Quellcode:
Was ist daran falsch? Ich gebe es ja wieder frei oder?
function IchGebeEinObjectZurueck : TMeinObject;
begin Result:=TMeinObject.Create; end; . . begin with IchGebeEinObjectZurueck do try // Tu was.. finally Free; end; end; |
Re: Funktionsrückgabe freigeben
Zitat:
|
Re: Funktionsrückgabe freigeben
Ups. Probier mal ShellAPI. In den Delphi Units sollte sie nicht zu finden sein, da es eine Windows Funktion ist. Und laut PDK ist sie in ShellAPI.h definiert, sollte also auch in Delphi in ShellAPI.pas zu finden sein.
|
Re: Funktionsrückgabe freigeben
.
Hey cool! Richtig viele Antworten! Und brauchbar dazu. Dickes Lob an alle! @IngoD7 ShellApi ist richtig. @Heiko und brechi Die von euch genannte Möglichkeit (war ja die gleiche) scheint zu funktionieren. Allerdings ist der Aufwand dann nicht wesentlich geringer, als der bei der Pozedur-Lösung. Wie aus den Antworten deutlich zu sehen ist, wird die Funktions-Lösung von den Meisten abgelehnt und die Prozedurlösung ist der absolut deutliche Favorit. Nachdem ich nun eure Antworten durchgelesen und eure Vorschläge getestet habe, bin ich (nach wie vor) überzeugter Anhänger der Procedure-Lösung! Zum Einen ist der Aufwand gegenüber der Funktions-Lösung nur unwesentlich größer. Zum Anderen ist die Procedure-Lösung deutlich besser lesbar, besser verwaltbar und besserer Programmierstil! OK, Käs-gess! ;-) Vielen Dank an alle! @Angel4585 Bliebe noch eine Frage: Wie zum Kuckuck sieht dein "Tu was.." aus? Im Ernst, wie willst du zum Beispiel eine Zuweisung durchführen, ohne die Funktion erneut aufzurufen? Beispiel:
Delphi-Quellcode:
Und trozdem auch dir vielen Dank!
function IchGebeEinObjectZurueck : TMeinObject;
begin Result:=TMeinObject.Create; end; . . begin with IchGebeEinObjectZurueck do try // Icon aus Exe auslesen und Image zuweisen Image1.Picture.Graphic := ??? finally Free; end; end; Grüße, Guido. |
Re: Funktionsrückgabe freigeben
Zitat:
Hirnblockade! :freak: Da wäre ich ums Verrecken heute nicht mehr drauf gekommen. |
Re: Funktionsrückgabe freigeben
Unabhängig von sonstigen Hirnschäden bei mir :mrgreen: habe ich noch eine Frage zum Verständnis:
Was wird denn überhaupt mit dem zwischenzeitlichen Erzeugen eines TIcons gewonnen? Oder anders: Was spricht gegen eine direkte Zuweisung des Handles?
Delphi-Quellcode:
Nachtrag:
Image1.Picture.Icon.Handle := ExtractIcon(HInstance, PCHAR('C:\Windows\NotePad.exe'), 0);
Natürlich immer fein mit
Delphi-Quellcode:
freigeben.
Image1.Picture.Icon.ReleaseHandle;
|
Re: Funktionsrückgabe freigeben
Moin Ingo,
gegen die Zuweisung des Handles spricht nichts, aber TIcon war hier ja auch nur als Beispielklasse gemeint ;-) |
Re: Funktionsrückgabe freigeben
Zitat:
|
Re: Funktionsrückgabe freigeben
Hallo Ingo.
Zitat:
Erinnerst du dich noch an das Thema dieses Threads? *nicht-bös-gemeint* Das Beispiel ist auch nicht schlecht gewählt! Denn es geht in diesem Thread NICHT darum, ein Icon zu extrahieren und einem Image-Control zuzuweisen. Wie Chris schon sagte, ist das TIcon nur ein Beispiel. Ginge es darum, hättest du natürlich recht: Durch die direkte Zuweisung des Icon-Handles aus der Rückgabe von ExtractIcon würde lediglich eine Referenz auf das "Icon[0]" der NotePad.exe-Ressourcedatei erzeugt und es würde auch nur einmal Speicher belegen. In diesem Thread geht es aber um was ganz anderes: Wie man Speicher freigibt, der durch Funktionen belegt wird, die ein Objekt als Rückgabe liefern. Ich denke, dass die Beiträge in diesem Thread und die Tests die ich durchgeführt habe aber deutlich zeigen, dass die Prozedur-Lösung der Funktion-Lösung vorzuziehen ist. Bei der Prozedur-Lösung kann man wirklich modular programmieren. Damit meine ich, dass der Code, der sich in der Prozedur befindet, soweit gekapselt ist, dass man sich außerhalb nicht mehr drum zu kümmern braucht. Man übergibt von außen einen Variablen-Parameter (Objekt), der dann auch außen freigegeben werden kann/muss und alles Andere wird innerhalb der Prozedur erledigt. Meine (Taskmanager-Minimal-) Tests mit der Funktion-Lösung haben folgendes ergeben: Trotz zwischenzeitlichem Erzeugen eines TIcons wächst bei vielfachem Aufrufen der Funktion die Speicherbelegung. Zwar um einiges langsamer, aber dennoch. Abschließend nochmals vielen Dank an alle! Eine(n) hab ich noch: Zitat:
Auch in der Hilfe zu ExtractIcon steht: Zitat:
Guido. |
Re: Funktionsrückgabe freigeben
Zitat:
Also die Funktion erzeug ein Object, der Zeiger auf dieses Object wird weitergegeben und in eine andere Variable gespeichert, könnte auch in 10 andere Variablen weitergegeben werden, es ist und bleibt EIN Object. Jedes Mal wenn die Funktion aufgerufen wird wird auch ein neues Object erzeugt, d.h. nach dem 10. Aufruf der Funktion sind es 10 Objekte. Wenn ich jedoch das ganze mit einer Prozedur erledige in der das Object falls es schon erzeugt wurde freigebe und danach erzeuge ist klar das es immer nur ein einziges bleibt. Sprich bei:
Delphi-Quellcode:
Da hantiere ich die ganze Zeit mit ein und der selben Variable, wodurch auch keine neuen Instanzen des Objects erzeugt werden.
procedure DieProzedur(var AMeinObject : TMeinObject);
begin if Assigned(AMeinObject) then FreeAndNil(AMeinObject); AMeinObject:=TMeinObject.Create; end; |
Re: Funktionsrückgabe freigeben
Wobei man dies:
Zitat:
Delphi-Quellcode:
procedure DieProzedur(var AMeinObject : TMeinObject);
begin AMeinObject.Free; AMeinObject := TMeinObject.Create; end; |
Re: Funktionsrückgabe freigeben
Hallo Angel4585.
Zitat:
Die Frage ist: Wie gebe ich den Speicher frei, den ein Funktion belegt, die ein Objekt zurückgibt? Ich habe den Eindruck, dass du das schon richtig verstanden hast: Zitat:
Zu deinem Beispiel mit der Klasse "TMeinObject": Zunächst mal ist es recht geschickt gemacht! Dadurch entsteht der Eindruck als würdest du auf meine Frage antworten. Die Frage war jedoch: Wie sieht dein "Tu was.." aus, wenn du das OBJEKT aus der Funktionsrückgabe im With-Block benutzen willst. Du hast in deiner Antwort jedoch einfach ein "Unter-Objekt" genommen! Das war NICHT die Frage! Du benutzt innerhalb des With-Blocks ein (Unter-)Objekt des Rückgabe-Objekts. In diesem Fall das Objekt einer Property. Wie gesagt, es war NICHT die Frage, wie ein ein Teil (Property) des Rückgabe-Objekts im With-Block benutzt werden kann, sondern wie das Rückgabe-Objekt selbst im With-Block benutzt werden kann. Um jedoch auf das eigentliche Thema zurückzukommen: Du hast in deinem Beispiel das Icon zwar (leer) erstellt, ihm aber kein Icon zugewiesen. Dadurch werden (fast) keine Ressourcen belegt. Der Sinn einer solchen Funktion ist natürlich, ein Icon auch zu benutzen/füllen. Wenn du das jedoch in deinem "TMeinObject"-Beispiel tust, sind wir so weit wie vorher!
Delphi-Quellcode:
Nun ergibt sich wieder das gleiche Ergebnis: Klickst du vielfach auf den Button, ist im Taskmanager ein langsames aber stetiges Ansteigen der Speicherbelegung zu erkennen!
type
TMeinObject = class(TObject) private FIcon : TIcon; public constructor Create; property ObjectIcon : TIcon read FIcon write FIcon; end; constructor TMeinObject.Create; begin FIcon:=TIcon.Create; end; function IchGebeEinObjectZurueck : TMeinObject; begin Result:=TMeinObject.Create; Result.ObjectIcon.LoadFromFile('C:\Test.ico'); // <- Speicher belegen end; procedure TForm1.Button1Click(Sender: TObject); begin with IchGebeEinObjectZurueck do try // Icon aus Exe auslesen und Image zuweisen Image1.Picture.Graphic := ObjectIcon finally Free; end; end; Aber nun genug davon. Wir haben offensichtlich alle (Thread-Teilnehmer) die Prozedur-Lösung zum Favoriten "erkoren"! Einschließlich dir selbst: Zitat:
Es wurden Möglichkeiten zur Freigabe von Objekt-Funktionsrückgaben in diesem Thread gezeigt. Jedoch können diese nicht wirklich überzeugen. Die Prozedur-Lösung hingegen stellt eine saubere, übersichtliche Möglichkeit dar. Damit ist meine Frage beantwortet. Nochmals danke an alle! Guido. |
Re: Funktionsrückgabe freigeben
beantwortet oder nicht :mrgreen:
es ist egal wie ein Objekt erzeugt wird, ob als Resultat einer Funktion oder einfach so, freigeben muss man es so oder so, also wenn du das Resultat der Funktion einer Variablen zuweist und diese dann freigibst, oder wie ich direkt mit dem With try finally free end arbeitest kommts auf das selbe raus. was ich nicht verstehe ist was es mit der Funktion auf sich hat, ist doch nichts anderes..
Delphi-Quellcode:
Ich nutze die Funktion wenn ich beim Erzeugen eines Objects jedesmal einen Schritt durchführen muss und die Variable selbst jedoch nicht benötige, also nur die "Unterobjekte".
//Das
FIcon:=TIcon.Create; //ist das selbe wie das function Irgendwas : TIcon; begin Result:=TIcon.Create; end; FIcon:=Irgendwas; Zum Beispiel(das verwende ich tatsächlich) wenn ich eine Datenbank anwendung habe und nur eine kurze Abfrage losschicke, dann hab ich nciht eine dauerhafte komponente irgendwo rumliegen, sondern erzeuge meine Query nur wenn ich sie brauche:
Delphi-Quellcode:
Ist jetzt nur ein Beispiel, aber für solche Anwendungen finde ich es einfach praktisch
function MyQuery(ASQL : string) : TZQuery;
begin Result:=TZQuery.Create(nil); Result.Connection:=DataModule1.ZConnection1; Result.SQL.text:=ASQL; end; //Dann spar ich mir dafür an anderen stellen jede Menge Code: with MyQuery('select * from tabelle where id="12345"') do try Active:=True;//Oderd auch Open, ExecSQL etc. //Und dann alles verarbeiten finally Free;//Und die temporäre Query freigeben. end; |
Re: Funktionsrückgabe freigeben
Hallo,
Zitat:
Gruß xaromz |
Re: Funktionsrückgabe freigeben
Hallo xaromz.
Schon lange nichts mehr von dir gehört! Es sei denn, in VB-Kreisen gibt es einen anderen xaromz!? Ansonsten: *freu* Zitat:
@Angel4585 Willst du dich jetzt an dem "Unterobjekt" festbeißen? Dann solltest du wohl einen eigenen Thread aufmachen! In diesem Thread geht es um das komplette Objekt einer Funktions-Rückgabe! Nehmen wir das Beispiel von ganz am Anfang und gestalten es der Klarheit wegen noch ein wenig einfacher:
Delphi-Quellcode:
Wie willst du das mit dem "with try finally free end" lösen? Und bitte, ... BITTE! nicht wieder über irgendwelche Unterobjekte! :wink:
function GetFileIcon(AFileName: string): TIcon;
begin Result := TIcon.Create; Result.LoadFromFile(AFileName); end; procedure TForm1.Button1Click(Sender: TObject); begin // Icon aus Exe auslesen und Image zuweisen Image1.Picture.Graphic := GetFileIcon('C:\Test.ico'); end; Guido. |
Re: Funktionsrückgabe freigeben
Hallo,
Zitat:
Die einzige Möglichkeit wäre hier folgende:
Delphi-Quellcode:
Etwas anderes macht ja with auch nicht, nur dass Du auf die Hilfsvariable nicht explizit zugreifen kannst. Das ist übrigens ein großer Nachteil dieses Konstrukts. Chrome hat das besser gelöst:
procedure TForm1.Button1Click(Sender: TObject);
var Icon: TIcon; begin // Icon aus Exe auslesen und Image zuweisen Icon := GetFileIcon('C:\Test.ico'); try Image1.Picture.Graphic := Icon; finally Icon.Free; end; end;
Delphi-Quellcode:
Gruß
procedure TForm1.Button1Click(Sender: TObject);
begin with Icon := GetFileIcon('C:\Test.ico') do begin Image1.Picture.Graphic := Icon; Icon.Free; end; end; xaromz |
Re: Funktionsrückgabe freigeben
Zitat:
|
Re: Funktionsrückgabe freigeben
IMHO ja, besser wäre da "Assign"
|
Re: Funktionsrückgabe freigeben
Hallo,
Zitat:
Zitat:
Zitat:
Delphi-Quellcode:
Die helper class könnte man noch in eine Bibliotheks-Unit auslagern und wiederverwenden. Die Lösung wirkt aber etwas unsauber und erreicht nicht die Eleganz des Chrome-Konstrukts. Letztlich spart sie nur etwas Schreibarbeit.
type
TObjectHelper = class helper for TObject function Instance: TObject; end; function TObjectHelper.Instance; begin Result := Self; end; procedure TForm1.Button1Click (Sender: TObject); begin // Icon aus Exe auslesen und Image zuweisen with GetFileIcon('C:\Test.ico') do try Image1.Picture.Graphic := TIcon(Instance); finally Free; end; end; Gruß Hawkeye |
Re: Funktionsrückgabe freigeben
Hallo Guido,
Zitat:
Zitat:
Mangels dieses Wissens würde ich es (sicherheitshalber) immer selbst freigeben - wie oben gesagt, wann immer ich dieses Icon nicht mehr brauche. Das kann auch (erst) bei Programmende sein. |
Re: Funktionsrückgabe freigeben
@Angel4585
Noch ein Wort zu meinem vorherigen Post: Als ich das geschrieben habe, war es schon spät und Guido war sehr, sehr müde! Als ich das heute nochmal durchgelesen habe, klang das irgendwie ein wenig hart! Eigentlich wollte ich da noch ein paar Smilies einfügen, um das aufzulockern. Der Leser sieht man ja nicht, wie der Schreiber das meint. Deshalb hier noch die Klarstellung, dass das nicht bös oder sonstwie abweisend gemeint war! :-D @Ingo Danke für Antwort! @xaromz Was ist Chrome? In Delphi geht dieses Konstrukt nicht.
Delphi-Quellcode:
@Hawkeye
procedure TForm1.Button1Click(Sender: TObject);
var Icon: TIcon; begin with Icon := GetFileIcon('C:\Test.ico') do begin Image1.Picture.Graphic := Icon; Icon.Free; end; end; Zitat:
Zitat:
Gruß, Guido. |
Re: Funktionsrückgabe freigeben
Hallo,
Zitat:
![]() Gruß xaromz |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:20 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