Free, FreeAndNil, Assigned a spol

vložil Radek Červinka 13. května 2011 21:39

I pokud je člověk začátečníkem, v Delphi narazí na objekty a třídy v podstatě hned - např. i formulář je objekt.

Jen pro úplnost: objekt je instancí třídy, ale to modří již vědí. Vytvoření objektu je provedeno voláním konstruktoru patřičné třídy. Následně objekt existuje v paměti dokud programátor neuzná za vhodné ho uvolnit (zjednodušeně).

var
  sl: TStringList;

begin
  sl := TStringList.Create;
  try
    …
  finally
    sl.Free; nebo FreeAndNil(sl);
  end;

Tohle zná snad každý. Vytvoříme instanci třídy #TStringList#, pak s ní pracujeme a nakonec ji uvolníme. Základní rozdíl mezi Free a FreeAndNil je, že oba přístupy uvolní objekt, ale FreeAndNil nastavuje proměnnou na nil. Jen pro úplnost, uvolnění je v sekci finally (vždycky!), protože v případě výjimky dojde ke korektnímu uvolnění - vytváříme tak robustní programy.

Malý test

Uvažujme proměnnou z předchozího případu.

a)
sl := TStringList.Create;
sl.Free;
sl.Free;

b)
sl := TStringList.Create;
FreeAndNil(sl);
sl.Free;

c)
sl := nil;
sl.Free;

Otázka: kdy nám to spadne? V případě a), b) nebo c)? A proč? Vrátíme se k tomu později.

TComponent

Malá odbočka. Pokud vytváříme objekt ze třídy, která je následníkem TComponent, máme i jinou možnost.

 constructor Create(AOwner: TComponent); virtual;

Všechny komponenty jsou následníkem TComponent, a pokud je vkládáme na formulář, VCL zajistí automatické vytvoření a předání formuláře jako AOwner. Pokud tedy je předán parametr do konstruktoru, je zaručeno, že vlastník automaticky uvolní vytvořenou komponentu. Pokud tedy vytváříme některé komponenty programově a nastavíme jim parametr, nemusíme (resp. jak podotkl Pepák v komentářích, spíše ani nesmíme) se starat o uvolnění. Pokud bude parametrem nil je třeba uvolňovat.

var 
  btn:TButton;
begin
  btn := TButton.Create(Self);
  btn.Parent := Self;
end;

Předpokládám, že Self je formulář.

TObject.Free

Starší Delphi (příklad je z Delphi 5):

procedure TObject.Free;
asm
        TEST    EAX,EAX
        JE      @@exit
        MOV     ECX,[EAX]
        MOV     DL,1
        CALL    dword ptr [ECX].vmtDestroy
@@exit:
end;

Delphi 2007+ (možná i starší)

procedure TObject.Free;
begin
  if Self <> nil then
    Destroy;
end;

Co nám to říká?

  • Že Free volá destructor Destroy, ale předtím provede test na nil. Takže kdo v testíku si myslel, že mu to spadne jen v případě a) tak měl pravdu. Resp. abych byl přesnější, tak a) je jediná možnost, že to buchne, ale není to vždy zaručeno - to jsou ty nejhorší chyby. FastMM tyto problémy sice dokáže detekovat (v debug módu), ale přesto pozor na to (viz starší články - dole tag FastMM).
  • Novější verze Delphi preferují PUREPASCAL proti ASM. Jednak se zlepšil optimalizátor (tj. jak se překládá do nativního kódu) kompilátoru, druhak zjednodušení kompilace pro jiné platformy. Výsledek je přeložen stejně jako by byl v asm.
  • Klidně můžete používat objekt <> nil místo Assigned(objekt). Výsledek je stejný, někdy možná i lepší.

Assigned má jedinou výhodu: jednoduše se mu dá předat bez @ parametr typu procedura.

Více už mne nenapadá, takže pokud k tomu něco máte, neváhejte použít komentáře.

P.S.: MS koupil Skype za cca 7 mld dolarů, čímž se stal nejdražší aplikací psanou v Delphi co znám. Pro porovnání: Embarcadero koupilo v květnu 2008 CodeGear divizi Borlandu (tj. Delphi a spol) za 23mil. dolarů + 7mil. v pohledávkách nebo co to je, tj. proti tomu za pakatel. Jelikož se právě Skype sotva vyhrabal do černých čísel tak je to opravdu pálka.

P.P.S: Pepákův YouTube Downloader (viz: zajímavé programy v Delphi v pravém sloupci) psaný v Delphi byl dnes na titulce iDnes.cz, takže mu blahopřeji (a díky i za propagaci Delphi). Doufám, že mu server vydržel ten nápor.

Tagy: , , ,

Začátečníci

Komentáře

14.5.2011 9:28:21 #

vuCZi

S tím Skypem jako Delphi aplikací to není úplně přesné. V Delphi je psaný pouze Win klient, komunikační protokol je tuším psaný v C nebo C++.

vuCZi

15.5.2011 13:16:52 #

pepak

Koukám, že si dosud nikdo nevšiml (a já taky ne, až teď), že v titulku je "Assign", ale má být "Assigned".

K TComponent: "Pokud tedy vytváříme některé komponenty programově a nastavíme jim parametr, nemusíme se starat o uvolnění." Skoro bych to změnil z "nemusíme" na "nesmíme" - pokud komponentu uvolním ručně, tak v Ownerovi zůstane původní odkaz, který už teď je neplatný. Tzn. musel bych se vedle uvolnění postarat ještě o to, aby ten původní odkaz zmizel z pole Owner.Components.

K iDnes: Server nápor vydržel, ale já skoro ne (tolik dotazů, už tolikrát zodpovězených a přesto stále opakovaných...).

pepak

20.5.2011 23:39:12 #

A

Vidím že fatální omyly knižních teoretiků publikované někdy před 15-ti lety se dosud nepodařilo vymýtit. Má to vypadat takhle. Nepochopení rozdílu Destroy vs Free vede k nezřízenému a neuváženému používání Free "však ono se nic nestane" nebo "dám to tam pro jistotu" až se to díky nepozornosti zavolá na neinicializované proměnné nebo zavolá 2x a je vymalováno. A je třeba zmínit že metoda Free jako taková vůbec není košér z hlediska OOP, je to jako vstoupit do výtahové šachty a až pak se teprve dívat zda tam výtah je nebo není a začátečníci by ji proto vůbec neměli používat, nýbrž if sl<>nil then sl.Destroy;

sl:=TStringList.Create;
try
..
finally
sl.Destroy;
end;


sl:=nil;
try
..
sl:=TStringList.Create;
finally
sl.Free;
end;

A

21.5.2011 9:42:53 #

radekc

Oba uvedené příklady od a@a jsou blbost.

radekc

21.5.2011 13:08:37 #

pepak

Ne snad přímo blbost, ale zbytečnost, v obou případech. Zažitý model

Promenna := TTrida.Create;
try
...
finally
  Promenna.Free;
  end;

je zcela v pořádku. I když to možná "zavedlo před patnácti lety pár knižních teoretiků". Košer to z hlediska OOP je, protože OOP mimo jiné odděluje data a metody objektu a není tedy problém, když se volá metoda, ke které neexistují data (pokud s tím daná metoda počítá a zařizuje se podle toho).

pepak

Komentování ukončeno

Naše nabídka

MVP
Ing. Radek Červinka - Embarcadero MVP
profil na linkedin, Twitter:@delphicz

Nabízím placené poradenství a konzultace v oblasti programování a vývoje SW.
Dále nabízíme i vývoj speciálního software na zakázku.

Neváhejte nás kontaktovat (i ohledně reklamy).

love Delphi

O Delphi.cz

Delphi je moderní RAD nástroj podporující tvorbu nativních aplikací pro platformu Win32, Win64, Mac OSX, Linux a na iPhone a Android.

Delphi.cz je nezávislý portál pro uživatele Delphi. Portál není koncipován pro úplné začátečníky, i když i ti se zde nebudou nudit, ale spíše na programátory, kteří již něco znají a chtějí své znalosti dále rozvíjet a sledovat novinky.

Poslední komentáře

Comment RSS

Dle měsíců