Delphi-PRAXiS
Seite 3 von 4     123 4      

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 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.


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:31 Uhr.
Seite 3 von 4     123 4      

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