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.