Comment libérer un TBitmap résultant d'une fonction?

Résolu
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 - 27 janv. 2007 à 17:16
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 - 28 janv. 2007 à 15:53
Salut à tous,





Une question existentielle me tourmente...
Je vous donne un petit exemple, ce sera plus simple:



function Bidouiller(BtmSource : TBitmap) : TBitmap;
begin
result := TBitmap.create;
... // ici, on bidouille le
... // BtmSource et on l'affecte
... // à result.
end;



Ca fonctionne très bien, mais la question qui me turlupine c'est que le TBitmap créé pour result n'est de fait jamais libéré.
Comment doit-on gérer cela?



Merci d'avance pour vos lumières.

17 réponses

Utilisateur anonyme
27 janv. 2007 à 18:26
Salut,

Je vais essayé d'etre un ptit moins expéditif que Julio .

Je me suis posé la même question il y a pas longtemps et j'ai opté pour la solution de Julio. Mais ca m'a turlupiné. Mais d'un autre coté result := TBitmap.create; me gène aussi beaucoup sur le principe peut etre encore plus que la question . En effet je ne concois pas (conceptuellement je parle) de créer le résultat d'une fonction. Du reste ce qui est valable pour un TBitMap l'est pour tout : TStringList, TMemo ect ect
3
JulioDelphi Messages postés 2226 Date d'inscription dimanche 5 octobre 2003 Statut Membre Dernière intervention 18 novembre 2010 14
27 janv. 2007 à 19:08
BINGO ^^
Le fBmpTemp doit etre libéré apres, une histoire de pointeur je pense.

************************************
var
Form1: TForm1;
fBmpTemp: TBitmap;

implementation

{$R *.dfm}

function Bidouiller1(BtmSource:TBitmap):TBitmap;
begin
result := TBitmap.create;
result.Height := BtmSource.Height div 2;
result.Width := BtmSource.Width div 2;
result.Canvas.Draw(0,0,BtmSource);
end;

function Bidouiller2(BtmSource:TBitmap):TBitmap;
begin
fBmpTemp := TBitmap.create;
fBmpTemp.Height := 1;
fBmpTemp.Width := 1;
fBmpTemp.Height := BtmSource.Height div 2;
fBmpTemp.Width := BtmSource.Width div 2;
fBmpTemp.Canvas.Draw(0,0,BtmSource);
result := fBmpTemp;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
Image2.Picture.Assign(Bidouiller1(Image1.Picture.Bitmap));
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
Image2.Picture.Assign(Bidouiller2(Image1.Picture.Bitmap));
fBmpTemp.free;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
Image2.Picture.Assign(nil);// PAS OK!
end;
3
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
27 janv. 2007 à 20:04
Salut,

alors oui ... sauf cas spéciaux

function Bidouiller1(BtmSource:TBitmap):TBitmap;
  begin
  result := TBitmap.create;
  result.Height := BtmSource.Height div 2;
  result.Width  := BtmSource.Width  div 2;
  result.Canvas.Draw(0,0,BtmSource);
end ;

Utilisation :

Var BMP : TBitmap;
Begin
  Try
    BMP : = Bidouiller1(Image1.Picture.Bitmap);
    .......
  Finally
    BMP.Free; // le Bitmap crée par la fonction Bidouiller1 est libéré ici
  End;
End;

 
@+
Cirec

<hr size ="2" />
3
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
28 janv. 2007 à 04:24
pffff .... un objet en retour de fonction ... n'importe quoi ... faut arreter la drogue les gars

procedure Bidouiller(Src, Dest : TBitmap);
begin
  if (not assigned(src)) or (not assigned(dest)) then

     exit;

  dest.Height := Src.Height shr 1;
  dest.Width  := Src.Width  shr 1;
  dest.Canvas.Draw(0, 0, Src);
end;

procedure TForm1.BtnDirectBidouilleClick(Sender: TObject);
begin
  Bidouiller(Image1.Picture.Bitmap, Image2.Picture.Bitmap);
end;

procedure TForm1.BtnBufferedBidouilleClick(Sender: TObject);
var Buffer : TBitmap;
begin
  Buffer := TBitmap.Create;
  try
    Bidouiller(Image1.Picture.Bitmap, Buffer);
    Image2.Picture.Bitmap.Assign(Buffer);
  finally
    Buffer.Free;
  end;
end;

end.

et en plus c'est plus rapide a s'executer en procedure et ça regle tout probleme de liberation car ca ne doit jamais etre la fonction ou procedure qui est en charge de la creation d'une instance d'objet!

3

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
JulioDelphi Messages postés 2226 Date d'inscription dimanche 5 octobre 2003 Statut Membre Dernière intervention 18 novembre 2010 14
27 janv. 2007 à 17:42
function Bidouiller(BtmSource : TBitmap) : TBitmap;
var
fBmpTemp: TBitmap;
begin
fBmpTemp := TBitmap.create;
... // ici, on bidouille le
... // BtmSource et on l'affecte
... // à result.
result := fBmpTemp;
fBmpTemp.free;
end;

(non testé)
0
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
27 janv. 2007 à 18:31
J'suis con ou quoi, moi?

Voici mon petit programme de test bidon:

implementation{$R *.dfm}

function Bidouiller1(BtmSource:TBitmap):TBitmap;//CA MARCHE
  begin
  result := TBitmap.create;
  result.Height := BtmSource.Height div 2;
  result.Width  := BtmSource.Width  div 2;
  result.Canvas.Draw(0,0,BtmSource);
end;

function Bidouiller2(BtmSource:TBitmap):TBitmap;//CA MARCHE PAS
  var  fBmpTemp: TBitmap;
  begin
  fBmpTemp := TBitmap.create;
  try
  fBmpTemp.Height := BtmSource.Height div 2;
  fBmpTemp.Width  := BtmSource.Width  div 2;
  fBmpTemp.Canvas.Draw(0,0,BtmSource);
  result.Height :=  fBmpTemp.Height;
  result.Width  :=  fBmpTemp.Width;
  //result := fBmpTemp; // -> ERREUR!  EAccessViolation
  //result.Assign(fBmpTemp); //-> ERREUR! EAccessViolation
  result.Canvas.Draw(0,0,fBmpTemp);//-> ERREUR! EAccessViolation
  finally fBmpTemp.free; end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Image2.Picture.Assign(Bidouiller1(Image1.Picture.Bitmap));// OK!
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  Image2.Picture.Assign(Bidouiller2(Image1.Picture.Bitmap));// PAS OK!
end;

end.
0
JulioDelphi Messages postés 2226 Date d'inscription dimanche 5 octobre 2003 Statut Membre Dernière intervention 18 novembre 2010 14
27 janv. 2007 à 19:10
désolé pour le bouton3, il marche mais j'ai laissé ton commentaire :p
0
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
27 janv. 2007 à 19:47
Merci les gars.
Mais autant en faire une procedure dans ce cas.

Julio a raison: sans doute une histoire de pointeur.
0
florenth Messages postés 1023 Date d'inscription dimanche 1 août 2004 Statut Membre Dernière intervention 17 août 2008 3
27 janv. 2007 à 19:47
Salut à tous,

Aïe aïe aïe ! Lorsque vous créez un objet, il faut absolument penser à le détruire ! Dans le code de Julio (le dernier), rien ne libère rien ! Le fait que l'objet soit crée par une fonciton ne change rien à la règle !

Il faut TOUJOURS affecter le résultat de la fonction dans une variable locale que l'on détruit après. Sinon, fuite de mémoire assurée.

[ Sauf, cas spéciaux, bien sûr, mais je n'en parlerais pas ici, n'est-ce pas Cirec ? ^^ ]

Bon, à bientôt pour un tutorial car ce genre de question à l'air d'en turbinlicoter plus d'un ...
0
JulioDelphi Messages postés 2226 Date d'inscription dimanche 5 octobre 2003 Statut Membre Dernière intervention 18 novembre 2010 14
27 janv. 2007 à 19:52
@florent : mais si on mets une variable en local, on a justement une erreur d'acces. Tu peux corriger mon code pour librer la mémoire ? merci
0
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
27 janv. 2007 à 20:04
La mémoire est bien libérée dans le code de Julio, non?

procedure TForm1.Button2Click(Sender: TObject);
begin
Image2.Picture.Assign(Bidouiller2(Image1.Picture.Bitmap));
fBmpTemp.free;
end;

Ou alors, j'comprends plus rien...
0
JulioDelphi Messages postés 2226 Date d'inscription dimanche 5 octobre 2003 Statut Membre Dernière intervention 18 novembre 2010 14
27 janv. 2007 à 20:21
Ah ok ! Mais donc on ne peut pas utiliser :
Image1.Picture.Bitmap.Assign(Bidouiller1(Image1.Picture.Bitmap));
?
Et si on est obligé de l'utiliser comme ça (pour une raison X ou Y), ma soluce reste t-elle bonne ou effectivement je ne libere rien.
0
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
27 janv. 2007 à 20:52
"Et si on est obligé de l'utiliser comme ça (pour une raison X ou Y), ma
soluce reste t-elle bonne ou effectivement je ne libere rien."

je dirai oui elle reste bonne ... mais je demanderai quand même confirmation a Florenth ... c'est lui le spécialiste

en effet c'est grâce à lui que j'ai enfin compris ce qui vous turlupine en ce moment
 
@+
Cirec

0
JulioDelphi Messages postés 2226 Date d'inscription dimanche 5 octobre 2003 Statut Membre Dernière intervention 18 novembre 2010 14
27 janv. 2007 à 21:02
ma mémoire est libérée florent, regarde mon bouton2
merci =)
0
Cirec Messages postés 3833 Date d'inscription vendredi 23 juillet 2004 Statut Modérateur Dernière intervention 18 septembre 2022 50
28 janv. 2007 à 14:51
alors la tu es en train de dire que Borland à fait n'importe quoi ... et qu'ils sont donc tous, par la même, sous l'effet de drogues

ça c'est n'importe quoi

le tout est de savoir comment faire pour liberer l'objet que la fonction vient de créer

étant donné les contrôles que tu es obligé de faire dans ta procédure je doute que ce soit plus rapide qu'une fonction
et même si c'était le cas ça se compte en nano-secondes ... pfff ...  donc imperceptible pour nous
 
@+
Cirec

0
florenth Messages postés 1023 Date d'inscription dimanche 1 août 2004 Statut Membre Dernière intervention 17 août 2008 3
28 janv. 2007 à 15:20
@f0xi: comme tu le dis si bien, faut arreter la drogue ... :-)

Une fonction, au niveau du code généré (assembleur), n'est ni plus ni moins d'une procédure.
Si tu veux t'en persuader, reparde le code ASM crée par Delphi sur ces deux appels :

- function CreerBitmap(W, H: Integer): TBitmap; register;
- procedure CreerBitmap(our Bmp: TBitmap; W, H: Integer); register;

C'est strictement la même chose. Une fonction retourne son résultat dans EAX.
Or, en convention Register, le premier paramètre d'une procedure est aussi EAX (sauf fonction d'objet), le deuxième EBX, puis ECX, et enfin les autres sont empilés, ce qui signifie que ces deux appels sont les mêmes... CQFD !

Allez, on te pardonne, c'est la neige qui réverbère dans tes neurones ... lol ^^
0
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
28 janv. 2007 à 15:53
Eh bein!
CS, c'est pas comme l'émission de Michel Drucker que je suis en train de regarder sur la 2.
Ici, ça se congratule moins tous azimuts!  mdr




Enfin, on apprend quand même plein de trucs de chacun d'entre vous.
Merci à tous.
0
Rejoignez-nous