[gelöst]TBitmap als Result einer function

Rund um die LCL und andere Komponenten
Antworten
hubblec4
Beiträge: 348
Registriert: Sa 25. Jan 2014, 17:50

[gelöst]TBitmap als Result einer function

Beitrag von hubblec4 »

Ich hätte da mal eine frage zu besagtem Thema.

Wenn ich eine solche function...

Code: Alles auswählen

function GetImage(const imgList:TImageList; const i:Integer):TBitmap;
var
  aPic: TBitmap;
begin  
   aPic:=TBitmap.Create; // Bitmap erzeugen
   imgList.GetBitmap(i,aPic);  // Bitmap in das Resualt laden
   Result:=aPic;
   aPic.Free; 
end; 
später für das setzen eines Glyphs (zum beispiel beim Speedbutton) verwende, kommt eine Fehlermeldung:
SIGSEGV Bei Adresse BAADF00D.

Wenn ich das "aPic.Free" auskommentiere (//aPic.Free) klappt alles wunderbar.
Allerdings frage ich mich nun da das aPic.Free fehlt ob der Speicher/das Objekt gelöscht wird?
Die funktion ist ja beendet und reicht das aus um das bild aus dem speicher zu entfernen?

Oder muss ich das generell anderes angehen da man ein Bitmap nicht als Resualt einer function augeben sollte?

hubble
Zuletzt geändert von hubblec4 am Sa 5. Mär 2016, 08:30, insgesamt 2-mal geändert.

wp_xyz
Beiträge: 5373
Registriert: Fr 8. Apr 2011, 09:01

Re: TBitmap als Resualt einer function

Beitrag von wp_xyz »

Am übersichtlichsten ist es, wenn du das Bitmap in derselben Routine zerstörst, in der du die Funktion aufgerufen hast. Klar, das ist nicht immer möglich, aber das folgende Beispiel wäre so etwas. Hier wird das Bitmap in der OnPaint Methode eines Panels gezeichnet und wird anschließend nicht mehr benötigt:

Code: Alles auswählen

procedure TForm1.PanelPaint(Sender: TObject);
var
  bmp: TBitmap;
begin
  bmp := GetBitmap(ImageList, 0);
  try
    TPanel(Sender).Canvas.Draw(0, 0, bmp);
  finally
    bmp.Free;
  end;
end;
Alternativ könntest du das Bitmap auch im Formular oder in der Unit global deklarieren, im FormCreate, wenn die ImageList geladen ist, erzeugen und im FormDestroy (oder sogar dem Finalization-Abschnitt der Unit) wieder freigeben. Damit sparst du dir das immerwährende Erzeugen/Zerstören des Bitmaps.

Allerdings gefällt mir diese Funktion überhaupt nicht weil ihr Name nicht darauf hinweist, dass hier etwas erzeugt wurde, was wieder zerstört werden muss, besser wäre z.B. "CreateFromImageList" o.ä.

Und speziell in diesem Fall wäre zu überlegen, ob die neue Funktion überhaupt nötig ist, da sie die Methode der ImageList nur als Funktion umschreibt:

Code: Alles auswählen

procedure TForm1.PanelPaint(Sender: TObject);
var
  bmp: TBitmap;
begin
  bmp := TBitmap.Create;       // hier wird etwas erzeugt...
  try
    ImageList.GetBitmap(0, bmp);
    TPanel(Sender).Canvas.Draw(0, 0, bmp);
  finally
    bmp.Free;                  // ... was hier wieder freigegeben wird.
  end;
end;

hubblec4
Beiträge: 348
Registriert: Sa 25. Jan 2014, 17:50

Re: TBitmap als Resualt einer function

Beitrag von hubblec4 »

mein beipiel habe ich stark reduziert, da meine eigentliche funktion auf mehrere Img listen zugreifen soll und des weiteren der Index(i) eigentlich auch erst innerhalb der funktion ermittelt wird.
Das erschien mir aber zuviel des guten und sollte nicht von der fragestellung ablenken.

Aus deinem post erkenne ich kein klares "nein darum geht es nicht", aber ich vermute mal das wird so nix mit der ausgabe.

Mir ist schon klar das das erzeugen der bitmap und das zerstören in ein und der selben routine stattfinden sollte.

Bleibt weiterhin die frage ob beim verlassen einer function ein erzeugtes bitmap mit freigegeben wird. wenn ja dann kann ich die funktion so lassen.

ansonsten werde ich mir nur den index von dem bild aus der entsprechenden Imagelist ausgeben lassen und muss dann in den weiteren proceduren das bitmap eben immer erzeugen und zerstören.

wp_xyz
Beiträge: 5373
Registriert: Fr 8. Apr 2011, 09:01

Re: TBitmap als Resualt einer function

Beitrag von wp_xyz »

hubblec4 hat geschrieben: Bleibt weiterhin die frage ob beim verlassen einer funtion ein erzeugtes bitmap mit freigegeben wird. wenn ja dann kann ich die funktion so lassen.
Das Bitmap wird beim Verlassen der Funktion natürlich nicht automatisch freigegeben, sonst könnte man in einer Funktion überhaupt keine Instanzen erzeugen, du brauchst es ja noch in der aufrufenden Prozedur. Deine Routine macht nichts anderes, als ein Bitmap als aPic zu erzeugen und dieses dann in Result umzubenennen, du kannst natürlich gleich mit "Result" arbeiten:

Code: Alles auswählen

function GetImage(const imgList:TImageList; const i:Integer):TBitmap;
begin 
   Result :=TBitmap.Create; // Bitmap erzeugen
   imgList.GetBitmap(i,Result);  // Bitmap in das Resualt laden
end; 
Und das Free muss definitiv raus!

Warf
Beiträge: 2270
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: TBitmap als Result einer function

Beitrag von Warf »

Wie wp bereits schon oben schrieb ist es übersichtlicher Create und Free in der selben Funktion zu haben. Zum Debuggen ist auch deutlich angenehmer dem Nutzer bzw der verwendenden Funktion selbst Create und Destroy zu überlassen, da man so einfach nur sehen muss: Zu jedem Create ein Free (das hasse ich auch abgrundtief an den DOM Klassen). Daher würde ich empfehlen einen Parameter zu verwenden:

Code: Alles auswählen

function GetImage(const b: TBitmap; const imgList: TImageList; const i: integer): boolean;
var
  aPic: TBitmap;
begin
  Result := True;
  aPic := TBitmap.Create; // Bitmap erzeugen
  try
    ImgList.GetBitmap(i, aPic);  // Bitmap in das Resualt laden
    if Assigned(b) then
      b.Assign(aPic)
    else
      Result := False;
  finally
    aPic.Free;
  end;
end;
 
//...
 
//Andere Prozedur
var b: TBitmap;
...
begin
  ...
  b:=TBitmap.Create;
  try
    GetImage(b, imglst, i);
    ...
  finally
    b.Free;
  end;
Wenn du es dennoch mit Funktionszurückgabe machen willst hat wp schon die Lösung geschrieben

hubblec4
Beiträge: 348
Registriert: Sa 25. Jan 2014, 17:50

Re: TBitmap als Result einer function

Beitrag von hubblec4 »

Hi Warf

auch bei deinem Beispiel ist es doch so, das von ausserhalb erstmal ein "b"(var : Tbitmap) erzeugt werden muss, welche dann in der function das bild zugewiesen bekommt.

Wie auch bei wp_xyz müsste ich dann immer dort wo ich bilder ändern muss, in den entsprechenden Prozeduren ein Create,Free für ein TBitmap machen.
Das wollte ich wie gesagt umgehen.

Alles klar. dann werde ich mir nur den index aus der ImgList holen und dann immer alles vor Ort erzeugen und zerstören.

Mathias
Beiträge: 7215
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: TBitmap als Result einer function

Beitrag von Mathias »

Dieses Bitmap Beispiel macht genau das selbe wie die Function FindAllFiles, welche bei der FPC RTL dabei ist.
Die Classe wird auch innerhalb der Function erzeugt.
Aber um die Freigabe muss man sich selbst kümmern.

http://wiki.freepascal.org/FindAllFiles
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 2270
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: TBitmap als Result einer function

Beitrag von Warf »

hubblec4 hat geschrieben:Hi Warf

auch bei deinem Beispiel ist es doch so, das von ausserhalb erstmal ein "b"(var : Tbitmap) erzeugt werden muss, welche dann in der function das bild zugewiesen bekommt.

Wie auch bei wp_xyz müsste ich dann immer dort wo ich bilder ändern muss, in den entsprechenden Prozeduren ein Create,Free für ein TBitmap machen.
Das wollte ich wie gesagt umgehen.

Alles klar. dann werde ich mir nur den index aus der ImgList holen und dann immer alles vor Ort erzeugen und zerstören.
Free musst du immer verwenden, ich bin nur der Meinung dass man dann sich um das Create auch selbst kümmer sollte, als Beispiel warum: Die Heaptrc Unit gibt bei Memoryleaks die Programmzeile an in der das Objekt erstellt wurde. Hast du jetzt sagen wir mal 10 Variablen, die du alle mit der Funktion erstellst, und du vergisst eins davon zu Deallocated (Free) gibt die Heaptrc die Zeile in der funktion. So musst du alle 10 Variablen überprüfen, erstellst du die Variablen separat, gehst du einfach in die Zeile die dir Heaptrc sagt, dann steht da z.B. BitmalXYZ := TBitmap.Create; und du weißt, du hast vergessen BitmapXYZ zu Deallocaten.

Wenn du ein Bild ändern willst musst du es nicht neu alloziieren (also Free und danach nochmal create) die Funktion oben von mir z.B. überschreibt das Komplette bild mit Assign, dadurch werden alle Daten von voher gelöscht und die neuen reingeschrieben

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2878
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: TBitmap als Result einer function

Beitrag von m.fuchs »

Warf hat geschrieben:Free musst du immer verwenden, ich bin nur der Meinung dass man dann sich um das Create auch selbst kümmer sollte, als Beispiel warum: Die Heaptrc Unit gibt bei Memoryleaks die Programmzeile an in der das Objekt erstellt wurde. Hast du jetzt sagen wir mal 10 Variablen, die du alle mit der Funktion erstellst, und du vergisst eins davon zu Deallocated (Free) gibt die Heaptrc die Zeile in der funktion. So musst du alle 10 Variablen überprüfen, erstellst du die Variablen separat, gehst du einfach in die Zeile die dir Heaptrc sagt, dann steht da z.B. BitmalXYZ := TBitmap.Create; und du weißt, du hast vergessen BitmapXYZ zu Deallocaten.
Naja, Heaptrc liefert schon ein bisschen mehr. Ein Beispiel:

Code: Alles auswählen

program heaptrctest;
{$mode objfpc}{$H+}
 
uses
  Heaptrc, Classes, SysUtils;
 
function CreateObject: TObject;
begin
  Result := TObject.Create;
end;
 
procedure Blafasel;
var
  o: TObject;
begin
  o := CreateObject;
end;
 
begin
  Blafasel;
end.
Wenn man das ganze aufruft, bekommt man schön die eigentlich Problemstelle zurück:

Code: Alles auswählen

$ ./heaptrctest 
Heap dump by heaptrc unit
22 memory blocks allocated : 1550/1552
21 memory blocks freed     : 1542/1544
1 unfreed memory blocks : 8
True heap size : 393216
True free heap : 393056
Should be : 393080
Call trace for block $00007F1D326E3160 size 8
  $00000000004001FE line 16 of heaptrctest.lpr
  $000000000040021E line 20 of heaptrctest.lpr
Gehen wir dann die Meldungen rückwärts durch landen wir zuerst in Zeile 20. Von dort wird Blafasel aufgerufen. In Zeile 16 (innerhalb von Blafasel) sehen wir auch schon unsere Problemstelle. Also alles kein Hexenwerk. Und auch keine ungewöhnliche Technik: https://de.wikipedia.org/wiki/Fabrikmethode
0118999881999119725-3

Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

hubblec4
Beiträge: 348
Registriert: Sa 25. Jan 2014, 17:50

Re: TBitmap als Result einer function

Beitrag von hubblec4 »

Danke für die zahlreichen erklärungen.
Ich denke ich habe das soweit verstanden und lasse mir nun nur noch den Index für das bild aus den verschiedenen ImageListen ausgeben.
Das erzeugen und zerstören wird dann immer lokal vorgenommen.

Sind ja auch nur zwei Codezeilen, also nichts was das Projekt unnötig auffbläht.

Antworten