Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Funktionsrückgabe freigeben (https://www.delphipraxis.net/88072-funktionsrueckgabe-freigeben.html)

Guido Eisenbeis 9. Mär 2007 16:05


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:
function GetFileIcon(AFileName: string; AIndex: integer = 0): TIcon;
begin
  Result := TIcon.Create;
  Result.Handle := ExtractIcon(HInstance, PCHAR(AFileName), AIndex);
end;
Ich habe zum Testen nun simpel und einfach eine Zuweisung vorgenommen, die auch tadellos funktioniert:

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
begin
  // Icon aus Exe auslesen und Image zuweisen
  Image1.Picture.Graphic := GetFileIcon('C:\Windows\NotePad.exe');
end;
Startet man nun den Taskmanager, so kann man schön beobachten, wie der Speicherbedarf dieser Testanwendung steigt, wenn man vielfach auf den Button klickt.

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.

hoika 9. Mär 2007 16:08

Re: Funktionsrückgabe freigeben
 
Hallo,

probier mal

Delphi-Quellcode:
Icon:= GetFileIcon('C:\Windows\NotePad.exe');
Image1.Picture.Graphic.Assign(Icon);
Icon.Free;

Heiko

NormanNG 9. Mär 2007 16:10

Re: Funktionsrückgabe freigeben
 
Hi,

das hat mit Funktion bzw. Prozecuren direkt doch nichts zu tun. Du schreibst doch selbst
Zitat:

Danach gebe ich diese TIcon-Variable im ButtonClick frei.
Wenn du das nur in der Prozedur-Variante machts, bleibt der Speicher eben bei der Funktion belegt und liegt als Trümmer im Speicher rum...

Guido Eisenbeis 9. Mär 2007 16:47

Re: Funktionsrückgabe freigeben
 
Zunächst mal danke für eure Antworten.

Zitat:

Zitat von hoika
Hallo,

probier mal

Delphi-Quellcode:
Icon:= GetFileIcon('C:\Windows\NotePad.exe');
Image1.Picture.Graphic.Assign(Icon);
Icon.Free;
Heiko

@Heiko:
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:

Zitat von NormanNG
das hat mit Funktion bzw. Prozecuren direkt doch nichts zu tun. Du schreibst doch selbst
Zitat:

Danach gebe ich diese TIcon-Variable im ButtonClick frei.
Wenn du das nur in der Prozedur-Variante machts, bleibt der Speicher eben bei der Funktion belegt und liegt als Trümmer im Speicher rum...

Genau das habe ich geschrieben, genau das ist die Fragestellung! Also, ich bin ja willig: Wie mache ich das?


Guido.

brechi 9. Mär 2007 17:14

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:
Icon := IrgendNefuntionDieNenIconZurückgibt;
// ... was mit icon amchen
Icon.Free;
Das was du da schreibst (mit Assign) is eigentlich so richtig gemacht, weiß nicht was du da noch freigeben willst ausser
Bitmap.Assign(nil) vill

sirius 9. Mär 2007 17:48

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?

Christian Seehase 9. Mär 2007 17:57

Re: Funktionsrückgabe freigeben
 
Moin Zusammen,

um das Ganze mal zu verallgemeinern:

Delphi-Quellcode:
// 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;
Es ginge statt der Prozedur natürlich auch eine Funktion, solange diese kein Objekt zurückliefert.

IngoD7 9. Mär 2007 18:02

Re: Funktionsrückgabe freigeben
 
Kleine Zwischenfrage:
Welche Unit brauche ich, um ExtractIcon(HInstance, PCHAR(AFileName), AIndex) benutzen zu können? :gruebel:
Danke.

Luckie 9. Mär 2007 18:06

Re: Funktionsrückgabe freigeben
 
Windows?

Angel4585 9. Mär 2007 18:07

Re: Funktionsrückgabe freigeben
 
Ich verwende immer sowas:

Delphi-Quellcode:
function IchGebeEinObjectZurueck : TMeinObject;
begin
Result:=TMeinObject.Create;
end;

.
.
begin
with IchGebeEinObjectZurueck do
  try
//    Tu was..
  finally
    Free;
    end;
end;
Was ist daran falsch? Ich gebe es ja wieder frei oder?

IngoD7 9. Mär 2007 18:10

Re: Funktionsrückgabe freigeben
 
Zitat:

Zitat von Luckie
Windows?

Njet, leider zu einfach. ---> Undefinierter Bezeichner: 'ExtractIcon'

Luckie 9. Mär 2007 18:14

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.

Guido Eisenbeis 9. Mär 2007 18:50

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:
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;
Und trozdem auch dir vielen Dank!

Grüße,
Guido.

IngoD7 9. Mär 2007 19:15

Re: Funktionsrückgabe freigeben
 
Zitat:

ShellAPI
:shock: Eigentlich kein ungewöhnlicher Kandidat. :wall:

Hirnblockade! :freak: Da wäre ich ums Verrecken heute nicht mehr drauf gekommen.

IngoD7 9. Mär 2007 19:41

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:
Image1.Picture.Icon.Handle := ExtractIcon(HInstance, PCHAR('C:\Windows\NotePad.exe'), 0);
Nachtrag:
Natürlich immer fein mit
Delphi-Quellcode:
Image1.Picture.Icon.ReleaseHandle;
freigeben.

Christian Seehase 9. Mär 2007 21:10

Re: Funktionsrückgabe freigeben
 
Moin Ingo,

gegen die Zuweisung des Handles spricht nichts, aber TIcon war hier ja auch nur als Beispielklasse gemeint ;-)

IngoD7 9. Mär 2007 21:26

Re: Funktionsrückgabe freigeben
 
Zitat:

Zitat von Christian Seehase
gegen die Zuweisung des Handles spricht nichts, aber TIcon war hier ja auch nur als Beispielklasse gemeint ;-)

Ja, stimmt. Aber dann war es ein etwas schlechtes Beispiel. ;)

Guido Eisenbeis 10. Mär 2007 02:58

Re: Funktionsrückgabe freigeben
 
Hallo Ingo.

Zitat:

Zitat von IngoD7
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:
Image1.Picture.Icon.Handle := ExtractIcon(HInstance, PCHAR('C:\Windows\NotePad.exe'), 0);

Irgendwie habe ich das Gefühl, in einem "rekursiven Threadaufrufing" zu stecken! :-D

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:

Zitat von IngoD7
Natürlich immer fein mit
Delphi-Quellcode:
Image1.Picture.Icon.ReleaseHandle;
freigeben.

An welcher Stelle des Codes würdest du das aufrufen?

Auch in der Hilfe zu ExtractIcon steht:
Zitat:

Remarks
You must destroy the icon handle returned by ExtractIcon by calling the DestroyIcon function.
Ich kann aber das Icon nicht freigeben, solange ich es in Image1 noch benötige. Muss man sich da noch bei Programmende drum kümmern, oder erfolgt dann eine Freigabe automatisch?


Guido.

Angel4585 10. Mär 2007 07:42

Re: Funktionsrückgabe freigeben
 
Zitat:

Zitat von Guido Eisenbeis
@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:
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;
end;
.
.
var
meinobject : TMeinObject;
begin
with IchGebeEinObjectZurueck do
  try
    // Icon aus Exe auslesen und Image zuweisen
    Image1.Picture.Graphic := ObjectIcon
  finally
    Free;
    end;
//So oder so:
meinobject:=IchGebeEinObjectZurueck;
Image1.Picture.Graphic := meinobject.ObjectIcon;
FreeAndNil(meinobject);
end;

Dazu muss ich sagen das ich das Problem nicht verstehe... den Speicher freigeben den eine Funktion belegt??
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:
procedure DieProzedur(var AMeinObject : TMeinObject);
begin
if Assigned(AMeinObject) then
  FreeAndNil(AMeinObject);
AMeinObject:=TMeinObject.Create;
end;
Da hantiere ich die ganze Zeit mit ein und der selben Variable, wodurch auch keine neuen Instanzen des Objects erzeugt werden.

Muetze1 10. Mär 2007 13:46

Re: Funktionsrückgabe freigeben
 
Wobei man dies:
Zitat:

Zitat von Angel4585
Delphi-Quellcode:
procedure DieProzedur(var AMeinObject : TMeinObject);
begin
if Assigned(AMeinObject) then
  FreeAndNil(AMeinObject);
AMeinObject:=TMeinObject.Create;
end;

so verkürzen kann:

Delphi-Quellcode:
procedure DieProzedur(var AMeinObject : TMeinObject);
begin
  AMeinObject.Free;
  AMeinObject := TMeinObject.Create;
end;

Guido Eisenbeis 10. Mär 2007 20:33

Re: Funktionsrückgabe freigeben
 
Hallo Angel4585.

Zitat:

Zitat von Angel4585
Dazu muss ich sagen das ich das Problem nicht verstehe... den Speicher freigeben den eine Funktion belegt??

Was gibt es daran nicht zu verstehen?
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:

Zitat von Angel4585
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.

Und die sollten wieder freigegeben werden, wenn man einen ordentlichen Programmierstil praktiziert!


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:
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;
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!


Aber nun genug davon. Wir haben offensichtlich alle (Thread-Teilnehmer) die Prozedur-Lösung zum Favoriten "erkoren"!
Einschließlich dir selbst:

Zitat:

Zitat von Angel4585
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.

Fazit:

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.

Angel4585 10. Mär 2007 22:29

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:
//Das
FIcon:=TIcon.Create;
//ist das selbe wie das

function Irgendwas : TIcon;
begin
Result:=TIcon.Create;
end;

FIcon:=Irgendwas;
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".

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:
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;
Ist jetzt nur ein Beispiel, aber für solche Anwendungen finde ich es einfach praktisch

xaromz 10. Mär 2007 23:06

Re: Funktionsrückgabe freigeben
 
Hallo,
Zitat:

Zitat von Guido Eisenbeis
Delphi-Quellcode:
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;
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!

Das ist ja auch klar. Das TMeinObjekt wird zwar freigegeben, das darin erstellte TIcon aber nicht. Du hast also ein Speicherleck erzeugt. Wenn Du im Destruktor von TMeinObject das TIcon aufräumst, steigt auch der Speicher nicht an.

Gruß
xaromz

Guido Eisenbeis 11. Mär 2007 00:10

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:

Zitat von xaromz
Hallo,
Das ist ja auch klar. Das TMeinObjekt wird zwar freigegeben, das darin erstellte TIcon aber nicht. Du hast also ein Speicherleck erzeugt. Wenn Du im Destruktor von TMeinObject das TIcon aufräumst, steigt auch der Speicher nicht an.

Danke! Genau das habe ich gemeint!


@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:
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;
Wie willst du das mit dem "with try finally free end" lösen? Und bitte, ... BITTE! nicht wieder über irgendwelche Unterobjekte! :wink:

Guido.

xaromz 11. Mär 2007 09:20

Re: Funktionsrückgabe freigeben
 
Hallo,
Zitat:

Zitat von Guido Eisenbeis
Nehmen wir das Beispiel von ganz am Anfang und gestalten es der Klarheit wegen noch ein wenig einfacher:

Delphi-Quellcode:
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;
Wie willst du das mit dem "with try finally free end" lösen? Und bitte, ... BITTE! nicht wieder über irgendwelche Unterobjekte! :wink:

Das lässt sich natürlich nicht ohne eine Hilfsvariable erledigen.
Die einzige Möglichkeit wäre hier folgende:
Delphi-Quellcode:
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;
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:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
begin
  with Icon := GetFileIcon('C:\Test.ico') do
  begin
    Image1.Picture.Graphic := Icon;
    Icon.Free;
  end;
end;
Gruß
xaromz

Angel4585 11. Mär 2007 09:37

Re: Funktionsrückgabe freigeben
 
Zitat:

Zitat von xaromz
Das lässt sich natürlich nicht ohne eine Hilfsvariable erledigen.
Die einzige Möglichkeit wäre hier folgende:
Delphi-Quellcode:
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;

Wird da nicht gleichzeitig auch Image1.Picture.Graphic freigegeben?

inherited 11. Mär 2007 09:41

Re: Funktionsrückgabe freigeben
 
IMHO ja, besser wäre da "Assign"

Hawkeye219 11. Mär 2007 10:30

Re: Funktionsrückgabe freigeben
 
Hallo,

Zitat:

Zitat von Angel4585
Wird da nicht gleichzeitig auch Image1.Picture.Graphic freigegeben?

Nein, intern wird beim Schreibzugriff auf die Eigenschaft Graphic eine neue TGraphic-Instanz angelegt, der dann mittels Assign() das übergebene Bild zugewiesen wird.

Zitat:

Zitat von inherited
IMHO ja, besser wäre da "Assign"

Das kann ins Auge gehen, da die Eigenschaft Graphic durchaus den Wert NIL enthalten kann.

Zitat:

Zitat von xaromz
Das lässt sich natürlich nicht ohne eine Hilfsvariable erledigen.

Als BDS-Nutzer könntest du das auch mit einer helper class erledigen:

Delphi-Quellcode:
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;
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.

Gruß Hawkeye

IngoD7 11. Mär 2007 12:35

Re: Funktionsrückgabe freigeben
 
Hallo Guido,

Zitat:

Zitat von Guido Eisenbeis
Eine(n) hab ich noch:

Zitat:

Zitat von IngoD7
Natürlich immer fein mit
Delphi-Quellcode:
Image1.Picture.Icon.ReleaseHandle;
freigeben.

An welcher Stelle des Codes würdest du das aufrufen?

Wann immer ich das aktuell angezeigte Icon (das belegt ja Speicher) nicht mehr anzeigen möchte (und ja daher das Handle auch nicht mehr benötige). Das kann also auch sein, wenn ich Icon.Handle ein anderes Handle (also quasi ein anderes Icon) zuweise. Da würde ich vorher das alte Handle releasen. So steht's auch in der Online-Hilfe zu Icon.ReleaseHandle.

Zitat:

Zitat von Guido Eisenbeis
Ich kann aber das Icon nicht freigeben, solange ich es in Image1 noch benötige. Muss man sich da noch bei Programmende drum kümmern, oder erfolgt dann eine Freigabe automatisch?

Das weiß ich leider nicht. Ich weiß nicht, wie Delphi bzw. ein Delphi-Compilat oder auch Windows selbst bei Programmende mit zuvor durch API-Funktionen belegten Speicherbereichen umgeht.

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.

Guido Eisenbeis 11. Mär 2007 19:10

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:
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;
@Hawkeye

Zitat:

Zitat von Angel4585
Wird da nicht gleichzeitig auch Image1.Picture.Graphic freigegeben?

Das hätte ich auch gedacht.

Zitat:

Zitat von Hawkeye219
Nein, intern wird beim Schreibzugriff auf die Eigenschaft Graphic eine neue TGraphic-Instanz angelegt, der dann mittels Assign() das übergebene Bild zugewiesen wird.

Hier der "Aha!"-Effekt! Und wieder was dazugelernt!

Gruß,
Guido.

xaromz 11. Mär 2007 21:05

Re: Funktionsrückgabe freigeben
 
Hallo,
Zitat:

Zitat von Guido Eisenbeis
@xaromz

Was ist Chrome? In Delphi geht dieses Konstrukt nicht.

www.chromesville.com

Gruß
xaromz


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:51 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz