Öncelikle belirtmek isterim ki; Delphi'de Free edilmiş ve nil'e eşitlenmiş (Pointer(0)) bir nesne işaretçisi üzerinden tekrar Free çağrımı yapabilirsiniz ve bu bir hataya neden olmaz. Ama neden ? Çünkü TObject.Free metodunda;
if Self <> nil then
Destroy;
gibi bir kod vardır. FreeAndNil var iken bu nimetten istifade etmemek bence çok yersiz ve gereksizdir. Basitçe aşağıdaki kodları çalıştırın:
procedure TForm1.Button1Click(Sender: TObject);
var
C : TComponent;
begin
c := TComponent.Create(nil);
ShowMessage('1-' + C.ToString);
C.Free;
ShowMessage('2-' + C.ToString);
end;
Ekranda, nesne yok edildikten sonra bile bir şeyler görüyorsunuz değil mi ? (Bu örnek için TComponent).
Peki bir de şu örneği çalıştırın:
procedure TForm1.Button1Click(Sender: TObject);
var
C : TComponent;
begin
c := TComponent.Create(nil);
ShowMessage('1-' + C.ToString);
FreeAndNil( C );
ShowMessage('2-' + C.ToString);
end;
Peki şimdi ne görüyorsunuz ? Bekleneni, yani bir Access Violation hatasını görüyor olmalısınız.
Free çağrımının tehlikesini fark edebildiniz mi ? Eğer edemedi iseniz, küçücük bir soru ile aklınızı meşgul etmeye çalışayım:
C isimli TComponent türündeki nesne Free edildiğinde; C için hafızada tahsis edilen alan işletim sistemine iade edilir; ancak C hâla hafızanın ilgili bölgesini işaret etmektedir. C nesnesi Free edildikten sonra; Memory Manager yeni bir TComponent türündeki D değişkeni için hafızada bir tahsisat yapsa ve tamamen tesadüfen C'nin gösterdiği lokasyonu ayırsa ne olur ?
Bu durumda; C ve D aynı hafıza bölgesini göstermektedirler. Ancak o bölge gerçekte artık tamamen farklı bir nesneye ait(D), oysa C'de aynı bölgeyi gösteriyor ve her ikiside (C ve D) bir TComponent türevi ise; bu durumda C üzerinden yapılan bir çağrı D'nin virtual metodlarının çağrılmasına neden olur.
Biliyorum biraz karmaşık yazmış olabilirim. Ancak bunu kağıt üstüne çizerek düşünür iseniz; ne demek istediğimi çok daha iyi anlayacaksınız.
Ayrıca FreeAndNil içindeki çağrımın sırasında bir hata yoktur. Bilerek ve isteyerek o şekilde dizayn edilmiştir. Bir nesnenin Destroy metodu içinden nesne instance pointer'ının kullanımı hatalıdır(değişken) ve bu hata tespit edilebilsin diye öncelikle instance pointer'ı nil'e set edilir, ardından Destroy'a dallanılır.
Free kullanmak gereksiz yere riske girmektir ve bunun mantıklı bir nedeni yoktur. C/C++ gibi dillerde uygulama geliştiren insanların null (nil) pointer'larla başlarının ne kadar derde girdiğini bilmeyenlerin bu hususta aynı hassasiyeti göstermeleri elbette çok fazla beklenemez.
Pointer'lar ile çalışmak dikkat gerektirir ve FreeAndNil, Assigned metodları bu hususta son derece faydalı metodlardır.
Free kullanıyorsanız ve instance pointer'ını nil'e eşitlemediyseniz; başınıza bir sürü sıkıntı gelebilir. Bunlardan en kompleksini yukarıda bir soru ile dikkatinize sundum. Bir başkası ve sıklıkla karşılaşılan ise multi free olayıdır. Free edilen bir nesne hafızadan zaten temizlenmiş ve ayrılan hafıza işletim sistemine yeniden iade edilmiştir. Ancak; ilgili değişken nil olmadığı için siz bu hafızanın iade edilip edilmediğini bilemezsiniz. Bu durumda; yeniden bir Free çağrımı yapma ihtimaliniz söz konusudur.
Böyle bir durumda neler olabilir ?
1- Daha önce tahsis edilmiş ve daha sonra işletim sistemine iade edilmiş hafıza bloğuna başka bir tahsisat yapılmamıştır ve yeni bir boşaltma talebi hatayla neticelenir.
2- Daha kötüsü; ilgili hafıza lokasyonuna başka bir nesne (X değişkeni diyelim) yerleşmiş olabilir. Sizin Free çağrınız o nesnenin kullandığı hafızayı işletim sistemine iade edebilir. Ardından X değişkenine erişmeye çalışırsınız ve anlamlandıramadığınız hatalar alırsınız.
....
Daha fazla bu husus hakkında konuşmayı gerekli görmüyorum. Free yerine FreeAndNil yazarak, bir çok sıkıntıyı daha başlamadan bertaraf edebilmek var iken; neden kapıyı pencereyi açık bırakıp, hırsızlara davetiye çıkartalım ki ?