free ve destroy metodları

Delphi'de kod yazma ile ilgili sorularınızı bu foruma yazabilirsiniz.
Kullanıcı avatarı
sadettinpolat
Moderator
Mesajlar: 2131
Kayıt: 07 Ara 2003 02:51
Konum: Ankara
İletişim:

free ve destroy metodları

Mesaj gönderen sadettinpolat »

Delphi de olusturdugumuz bir nesneyi isimiz bittekten sonra genel olarak asagidaki sekilde yok ederiz.

Kod: Tümünü seç

procedure TForm1.Button1Click(Sender: TObject);
var
nesne:TStringList;
begin
nesne:=TStringList.Create;

//bir takım işlemler ve ardindan

nesne.Free;
nesne := nil;
// bu iki satir yerine FreeAndNil de kullanabiliriz tabi….
end;
soru 1) Değişkeni neden delphi değilde ben nile atamak zorunda kalıyorum ?
soru 2) Nesneyi yok etmek için neden destroy değilde free metodunu çağırmam gerekir ?
soru 3) Free metodu statikken Destroy metodu neden sanal tanımlanmıştır ?
soru 4) Destroy metodunu çağırmak tehlikeliyse ve free metodu onun işini görüyorsa destroy metodu neden protected değilde public tanımlanmıştır ?
soru 5) Free metodu self <> nil then Destroy gibi bir satırla destroy metodunu çağırır. Program bu satıra kadar başarılı bir şekilde gelmişse self henüz yok edilmemiş geçerli bir nesne değil midir? Neden nesnenin nil olup olmadığı kontrol edilmektedir ?
"Sevmek, ne zaman vazgececegini bilmektir." dedi, bana.

---
http://sadettinpolat.blogspot.com/
t-hex
Kıdemli Üye
Mesajlar: 531
Kayıt: 18 Mar 2005 02:45
Konum: İstanbul/Antalya
İletişim:

Mesaj gönderen t-hex »

Bir nesne yaratılırken, yani constructordaki kodlar çalışırken bir exception ortaya çıkarsa direk olarak destructor (Destroy) çağrılır. Destructor'ın amacı constructorın yarattıklarını yok etmektir. Verdiğim örnekte exception oluştuğundan dolayı destructor daha yaratılmamış nesneleri de yok etmeye çalışacak dolayısıyla iş çorbaya dönecektir. İşte bu yüzden Destroy metodunun nil kontrolü yapması gerekir. Sürekli bu kontrolü yapmaktansa Free diyorlar.

if Self <> nil diye bir kod gerçekten çok tuhaf duruyor ama işte Delphi bu, çok fazla takılmamak lazım bu gibi durumlara çünkü Delphi tam anlamıyla OOP değil.

3.soru için : Nesnenin asıl destructor'u Destroy metodu olduğu için türetilen sınıflarda override edilebilsin diye virtual olarak tanımlanmış. Free metodu sadece self <> nil kontrolü yapacağı ve destructorı çağıracağı için statik kalmış.
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Güzel sorular bunlar sadettin.

t-hex açıklamasını gayet güzel yapmış. Ben biraz örnekleyeyim istedim.

THede isimli bir class'ımız olsun. Biz bunu kullanmak için ne yaparız? Create constructor'u ile yaratırız. Peki bu yaratma işlemi esnasında constructor içindeki bir kodda exception oluşursa ne olur? Nesnemiz yaratılır mı yine de? Hayır. Peki yaratılmamış ve bellekte aslında olmayan bir nesneyi destroy ile yoketmeye çalışırsak ne olur?

Kod: Tümünü seç

Hede:= THede.Create;   <-- Burada exception oluşursa?
try

finally
  Hede.Free;  <-- Hede yaratıldı mı ki?
end;
Free bu sorunu gayet güzel çözüyor."Eğer Self nil değilse Destroy'u işlet." diyerek destructor içinde olabilecek, temizlik yapan kodları işletmeye mani oluyor.
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Nesne pointer'ını taşıyan variable'ı nesne free olduktan sonra Delphi neden nil yapsın anlayamadım? O zavallı bir pointer. Nesne ile bir ilgisi yok ki. Hem belki ben free yapılmış nesnenin pointerını bilmek istiyorum. ;)
poshet303
Üye
Mesajlar: 235
Kayıt: 26 Eki 2005 01:15

Mesaj gönderen poshet303 »

Merhaba;
Sorular gerçektende güzel.

Cevap1: Marco Cantu.
Free is a method of the TObject class, inherited by all other classes. The Free method basically checks whether the
current object (Self) is not nil before calling the Destroy virtual destructor. Free doesn't set the object to nil
automatically; this is something you should do yourself! The object doesn't know which variables may be referring to it, so it has no way to set them all to nil.
Yani bir nesne örneği hangi değişkenlerin kendine işaret ettiğini bilemez.
X:TEdit;X:=TEdit.Create;Y:=X;Z:=X;
Delphi şimdi hangisini nil yapsın.

Cevap2:Pascal, C den farklı olarak her şeyi güvenli yapmak ister. FREE çağrısı aslında güvenli bir DESTROY çağrısı yapmanın basit yoludur.(zaten yukarıda anlatılmış)

Cevap3:Free metodunun kodundan anlaşılıyor zaten asıl işi DESTROY yapıyor FREE sadece güvenli DESTROY çağrısı yapıyor. FREE yi (override) ezmeye ihtiyacımız olmaz.

Cevap4:Cevap basit. override etmemiz için. Create içinde, örneğin sınıf içinde bir nesne örneği oluşturursak (ve ilgili nesnenin bir owner ı yoksa) DESTROY da ona ayrılan belleği geri verebiliriz.

Cevap5:Bunun cevabı zaten verilmiş.

...Delphi bu, çok fazla takılmamak lazım bu gibi durumlara çünkü Delphi tam anlamıyla OOP değil.
Bu konu ezelden beri tartışılmıştır. Aksini iddaa edenlerde var. Sonuçlandırılmıştır diyemeyiz bu birazda fanatizmle ilgili.
Kullanıcı avatarı
undefined
Moderator
Mesajlar: 565
Kayıt: 06 Eki 2003 12:01
Konum: Bursa
İletişim:

Mesaj gönderen undefined »

soru 5) Free metodu self <> nil then Destroy gibi bir satırla destroy metodunu çağırır. Program bu satıra kadar başarılı bir şekilde gelmişse self henüz yok edilmemiş geçerli bir nesne değil midir? Neden nesnenin nil olup olmadığı kontrol edilmektedir ?
Bunun OOP olup olmamasıyla ne alakası var?

Coderlord cevabı vermiş bu sorunun zaten. İlave edecek olursam Destroy metodu illa create edilmiş bir object instancendan çağırlacak diye birşey yok. Bir Class'ın instance'ı olmasa bile çalışabilir kodları da process'in ".text" bölümünde readonly olarak durur. Object yaratılırsa heapte yer ayrılarak bu Classın üyelerinin içeriği tutulur. Bu object'ten bir kod çalıştırırsak self değeri bu objectin heapteki adresini referans edecek şekilde bu kodlar ".text" sectionından çalışır.
Delphi'nin bu kontrolü yapması doğal birşeydir. Self nil gelmişse destructor'ın hangi objecti destroy etmesini beklersin? Nil hiç birşeyi referans etmezse olmayan bir object için destructorı niye çalıştıralım?
Adamlar birşey yazmışsa bişey biliyorlarda yazıyorlar herhalde :D

Ayrıca, mesela C++ ta delete objectbilmemne dediğinizde en çocuk Classtan başlanarak sırasıyla en ata Classın destructor metodu çağrılacak şekilde katı bir sınırlaması vardır. Bu sıra, New objectbilmemne de ata dan çocuğa olacak şekilde değişir. Delphi'de böyle bir sınırlama yoktur.

.Net ve Java nın otomatik çöp toplama sistemleri vardır. Bu onların mimarilerinden ileri gelen birşey. Dilmiş, OOPmiş bunla ilgili değildir.

Ayrıca üşengeçler kolaylık olsun diye "FreeandNil(objectbilmemne)" yi kullanabilirler :D
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Aslında Self'in ne anlama geldiği önemli.

Bir class'ı yarattığınızda bellekten yer ayrılır. Fakat bu yer object'in tuttuğu variable'lar içindir. Kodu için değil! Kod her zaman aynı lokasyonda işletilir. Method inheritance'larda işler biraz daha karmaşık. Araya VMT de girer. Neyse konu bu değil.

Kod: Tümünü seç

type
  THede = class(TObject)
  private
    FList: TList;
  public
    constructor Create; virtual;
    destructor Destroy; override;
  end;

constructor THede.Create;
begin
  FList:= TList.Create;
end;

destructor THede.Destroy;
begin
  FList.Free;
end;
Bu class, constructor'ı ile çağırıldığında bellekte yer ayrılacak. Bu yer aslında FList'e ulaşabilmemiz için ayrılıyor. Daha sonra bir TList yaratılıyor ve FList değişkenine pointer'ı atanıyor.

Şimdi bir sorun oldu ve FList:= TList.Create çağrısı exception ile sonuçlandı diyelim.

Peki güzel.. :) Biz de gittik Hede.Destroy yaptık. Burada destructor işletilirken FList.Free çağrısında şişer. Çünkü Self.FList hiçbir yeri işaret etmemektedir. Evet doğru. Sınıf methodu içerisinde FList.Free olarak yazılan şey compiler tarafından aslında Self.FList.Free olarak işletilir. Bunun nedeni bellekte olabilecek diğer THede instance'larının FList variable ları ile karışmaması. İşte OOP. :) Daha create'de exception yediğimiz için objenin variable'ları için bellekte yer ayrılmamış olacak ve FList tanımsız görünecektir. En iyi ihtimalle, hakkınız olmayan bir belleği okumaya veya yazmaya çalıştığınızı söyleyen bir hata mesajı çıkacaktır. :)

Nesnelerin iç yapısı hakkında daha faza detay için buradaki ve buradaki makaleler okunabilir.
aLonE CoDeR
Kıdemli Üye
Mesajlar: 1223
Kayıt: 26 Nis 2005 04:08

Mesaj gönderen aLonE CoDeR »

undefined yazdı: Ayrıca üşengeçler kolaylık olsun diye "FreeandNil(objectbilmemne)" yi kullanabilirler :D
Bu kanaate nerden vardın (yukarda anlattıklarımdan demezsin umarım!)?FreeAndNil tercih edilmesi gereken birçok durum var.Tıpkı try,except,finally blokları gibi..Delphi gerçekten tam olarak OOP değil.Javadaki kalıtım, akıtma ve son dönemin hibernate olayını incelersek bunun böyle olmadığını gayet rahat görebiliriz :idea:
t-hex
Kıdemli Üye
Mesajlar: 531
Kayıt: 18 Mar 2005 02:45
Konum: İstanbul/Antalya
İletişim:

Mesaj gönderen t-hex »

poshet303 yazdı:Bu konu ezelden beri tartışılmıştır. Aksini iddaa edenlerde var. Sonuçlandırılmıştır diyemeyiz bu birazda fanatizmle ilgili.
Yok hocam fanatizmle alakalı falan değil. Çok basit bir örnek vericem:

Private tanımlanan alanlara ve yordamlara sadece tanımlandığı sınıf içinde ulaşılabilir. Protected alanlara ise türetilen sınıflar ulaşabilir. Bunlar OOP kabulüdür, öyle olması lazım. Fakat Delphi de aynı unit içindeki bütün sınıflar diğerlerinin private/protected alan ve yordamlara ulaşabiliyor.

Zaten bu yüzden Delphi.NET'te strictly private, strictly protected diye yeni keywordler ekledir.
poshet303
Üye
Mesajlar: 235
Kayıt: 26 Eki 2005 01:15

Mesaj gönderen poshet303 »

Sorun belkide geleneklerdir.

Pascal c gibi diller OOP den önce geliştirilmiş diller. Her ikiside OOP ye göre yeniden düzenlenmiş. Aslında C++ için ne kadar C den geliştirilmiştir denebilir bilmiyorum (hep öyle olduğu söylenir ama).

Eskinin kolaylıklarını bırakamamışlar sanırım. Yalıtımı class bazında değil unit bazında yapmışlar. Benzer özellikli sınıfları aynı unit te yazıp bu esneklikten faydalanmışlar.

Bu açıdan söylediğiniz doğru Delphi OOP nin tüm özellikleri sağlamıyor olabilir. Ama C++ ın çoklu kalıtımı içinde aynı şeyi duymuştum. Çoklu kalıtımın OOP mantığına ters düştüğünü söyleyenler vardı.

Java ile kıyasa gelince. Java ADA gibi dillere modern dillerde deniyor. Bunlar yakın zamanda tasarlanmış diller. Eski deneyimlerin göz önüne alınması ile şekillenmiş diller. O nedenle yeni dilleri eskileri ile kıyaslamak biraz Tuzla Jeep ile Megan ı kıyaslamaya benziyor.

Genelde programlama dilleri ile ilgili tartışmalar şu cümleyle biter. "Hangi dili kullanacağınız amaçlarınıza bağlıdır". Neticede daha iyi OOP olan Java ile işletim sistemi herhalde yazamazsınız (sanki pascal ile yazılabilirmiş gibi.). Delphi yi daha çok DB lere erişmek için kullanıyoruz. Bunun için gayet yetenekli. Zaten ilk çıktığı yıllarda Borland ın iddeası şuydu "VB kadat basit C kadar güçlü". Yani ne VB kadar kolay nede C kadar güçlü. :)


Not: Interbase in MS Visual C ile derlendiğini biliyormuydunuz?
aLonE CoDeR
Kıdemli Üye
Mesajlar: 1223
Kayıt: 26 Nis 2005 04:08

Mesaj gönderen aLonE CoDeR »

poshet303 yazdı: Java ile kıyasa gelince. Java ADA gibi dillere modern dillerde deniyor. Bunlar yakın zamanda tasarlanmış diller. Eski deneyimlerin göz önüne alınması ile şekillenmiş diller. O nedenle yeni dilleri eskileri ile kıyaslamak biraz Tuzla Jeep ile Megan ı kıyaslamaya benziyor.
Javanın geliştirilmesiyle OOP'nin ortaya çıktığı tarihlere bakarsan işin öyle olmadığını görürsün.OOP Pascal'ın son dönemlerinde de vardı yani Object Pascal, Turbo Pascal zaten bunları destekliyor.Kaldı ki Delphi'ye geçiş yani tamamen visual programlamaya girişin başladığı bu dönemdir ve alt yapısında da OOP vardır.Peki Delphi neden tam anlamıyla OOP değil?Çünkü tam anlamıyla OOP destekleyen bir ide, özellikle geliştirilme süreci göz önüne alındığında, şu an Delphi'nin belki 3.versiyonu vardı piyasada ve Borland bu kadar büyüyemezdi kesinlikle.Zaten öyle olmasaydı şimdi Java da son derece esnek bir ide (eclipse için söylemiyorum bunu..) olurdu ve geliştirilen projelerde o şekilde olabilirdi.Java'da proje geliştirmekle Delphi'de proje geliştirmek arasında çok çok ciddi farklılık olmadığını söyleyebilir misin?Java son derece kuralcıyken Delphi çoğu yerde esnektir.Zaten tam olarak OOP olamamasının en büyük nedeni de bu değil mi :idea:
poshet303
Üye
Mesajlar: 235
Kayıt: 26 Eki 2005 01:15

Mesaj gönderen poshet303 »

Javanın geliştirilmesiyle OOP'nin ortaya çıktığı tarihlere bakarsan işin öyle olmadığını görürsün
Bu kısmı anlamadım Java nın OOP den önce olduğunu yada OOP ile aynı dönemde tasarlandığınımı söylüyorsunuz?

OOP Pascal'ın son dönemlerinde de vardı yani Object Pascal, Turbo Pascal zaten bunları destekliyor
Turbo Pascal 5.5 ile OOP oldu yani uzun sayılabilecek bir süre.
Ben aksini söylemedim. Delphi de kolaylık için böyle yapılmış olduğunu (tahmin ile) söyledim.
Eskinin kolaylıklarını bırakamamışlar sanırım. Yalıtımı class bazında değil unit bazında yapmışlar. Benzer özellikli sınıfları aynı unit te yazıp bu esneklikten faydalanmışlar.
Demişim. Burda eskiden kasıt OOP den önce moda olan (ve halada geçerli olan) yapısal programlama. Yapısal programlamada fonksiyon(procdure) ve unit ler en temel özellikler (bir de goto kullanılmaması :) )


Java IDE lerinin yeteneklerini kısıtlı olması Java nın kısmen yorumlanan (JavaVM) platform bağımsız (kısmen) bir dil olaması olabilir mi?
aLonE CoDeR
Kıdemli Üye
Mesajlar: 1223
Kayıt: 26 Nis 2005 04:08

Mesaj gönderen aLonE CoDeR »

Evet javanın temelinin de eskilere dayandığını, daha doğrusu yeni nesil dil olarak nitelendirilmemesi gerektiğini vs..

Hayır JVM yorumlayıcısından kaynaklanan bir durum değil, zira yorumlayıcıyla derleyicinin arasında yaptıkları işlemin birbirinin tersi olmasından öte bir fark yok.Olay javanın daha kuralcı olmasından kaynaklanıyor vs.vs.
Kullanıcı avatarı
sadettinpolat
Moderator
Mesajlar: 2131
Kayıt: 07 Ara 2003 02:51
Konum: Ankara
İletişim:

Re: free ve destroy metodları

Mesaj gönderen sadettinpolat »

kendi adıma 5 soru sordum ama daha fazlasını aldım. cevaplar icin herkese tesekkur ederim ama bazi seyler daha henuz tam olarak yerine oturmadi. onun icin sorulara devam :)
sadettinpolat yazdı: soru 1) Değişkeni neden delphi değilde ben nile atamak zorunda kalıyorum ?
poshet303 yazdı: Yani bir nesne örneği hangi değişkenlerin kendine işaret ettiğini bilemez.
X:TEdit;X:=TEdit.Create;Y:=X;Z:=X;
Delphi şimdi hangisini nil yapsın.
bu soru gitti :)
sadettinpolat yazdı: soru 2) Nesneyi yok etmek için neden destroy değilde free metodunu çağırmam gerekir ?
free, self <> nil kontrolu yaptigi icin destroya oranla daha güvenlidir tamam ama sonucta free metodu da nesnenin bir parçası değil mi ? hafizadan serbest birakilmis bir nesnenin free metodu nasil olurda access violatin hatasi vermeden duzgun calisabilir ? Derleyici statik metodlari ve sanal metodlari isletirken arka planda neler karistirir ?


Kod: Tümünü seç

procedure TForm1.Button2Click(Sender: TObject);
var
nesne:THede;
begin
  nesne :=THede.Create;
  nesne.Free;
  nesne := nil;
  nesne.Free; 
 //bu free uzayda mi durmaktadir ? nesnenin bir metodu  degil midir
 //ama   nesne yok edilmistir...
end;
koddaki ikinci free cagrisi neden hataya yol acmaz ?
sadettinpolat yazdı: soru 3) Free metodu statikken Destroy metodu neden sanal tanımlanmıştır ?
t-hex yazdı: 3.soru için : Nesnenin asıl destructor'u Destroy metodu olduğu için türetilen sınıflarda override edilebilsin diye virtual olarak tanımlanmış. Free metodu sadece self <> nil kontrolü yapacağı ve destructorı çağıracağı için statik kalmış.
bu da okeydir :)

sadettinpolat yazdı: soru 4) Destroy metodunu çağırmak tehlikeliyse ve free metodu onun işini görüyorsa destroy metodu neden protected değilde public tanımlanmıştır ?
Baska bir problemle ugrasirken Constructor metodu gizlemeye calismistim. Metodu private ya da protected bolumde tanimlamak hic bir etki yapmadi. nereye yazarsam yazayım Create hep Public oluyordu. Destroy da aynıdır diye düşündüm ama Protected alanda tanımladığımda Destroy gizlenmişti. Nesne.Destroy yazamadım. Destroy gizlenebiliyorsa Public yerine Protested tanımlanabilir. Üstelik daha sonra üretilecek sınıflar eger arzu ederlerse Destroyu yine ezebilirler ve bu protected yokedici free metodu kullanılarak çağrılabilir ama nedense public tanımlanmış. Sanki bazı yerlerde free değilde Destroy çağırmak gerekliymiş gibi bir his veriyor insana...

coderlord yazdı:

Kod: Tümünü seç

Hede:= THede.Create;   <-- Burada exception oluşursa?
try

finally
  Hede.Free;  <-- Hede yaratıldı mı ki?
end; 

burayi tam olarak anlayamadim galiba. Yukaridaki kodda Create metodunda ortaya cikacak bir hata sonucu Hede.Free; satırı çalışır mı ?
THede.Create cagrisi try - finally blogu arasinda değil ki !


delphi ve oop konusunda ise bana gore pascal oop'u tam olarak destekler. bazi seyleri javadan farkli yapmasi pascalin tam olarak oop'u desteklemedigi manasina gelmez. Private alanlarin ayni unit icindeki diger nesneler tarafindan kullanilmasi bir avantajda olabilir yerine gore. Yok illa gormesin diyorsanız nesneleri ayrı ayrı unitlere koyabilirsiniz.

if self<> nil then gibi satırlar ise delphinin nesne referans modelinin bir sonucu. java da bir degiskeni deklare etmek onu yaratmak manasina gelir ama delphide once degiskeni tanimlarsiniz ardindan nesnenin yapilandiricisi cagrilarak degiskene nesnenin adresini atarsiniz.
bunlar oop tan ziyade biraz mimari konular bana gore, tipki java ve .net teki ki cop toplayici gibi.
"Sevmek, ne zaman vazgececegini bilmektir." dedi, bana.

---
http://sadettinpolat.blogspot.com/
t-hex
Kıdemli Üye
Mesajlar: 531
Kayıt: 18 Mar 2005 02:45
Konum: İstanbul/Antalya
İletişim:

Mesaj gönderen t-hex »

saadettinpolat yazdı:if self<> nil then gibi satırlar ise delphinin nesne referans modelinin bir sonucu. java da bir degiskeni deklare etmek onu yaratmak manasina gelir ama delphide once degiskeni tanimlarsiniz ardindan nesnenin yapilandiricisi cagrilarak degiskene nesnenin adresini atarsiniz.
Java da nesne referans modelini kullanıyor. Sanırım C++ demek istediniz. Çünkü C++, Plain Object Model kullandığından sadece tanımlamak yeterlidir. (default constructor varsa)
poshet303 yazdı:Java IDE lerinin yeteneklerini kısıtlı olması Java nın kısmen yorumlanan (JavaVM) platform bağımsız (kısmen) bir dil olaması olabilir mi?
Java IDE'lerinin yetenekleri kısıtlı olması diye bir şey düşünemiyorum. Yani IDE ve dil tamamiyle farklı. Bu kısıtlığın tek nedeni geliştirenlerin hayalgücünün kısıtlı olması olabilir. Fakat yavaşlık diyorsanız, onun bir nedeni swing'in yavaş olması. Platforma uygun kodla gayet hızlı bir arayüz yazılabilir.
poshet303 yazdı:C++ ın çoklu kalıtımı içinde aynı şeyi duymuştum. Çoklu kalıtımın OOP mantığına ters düştüğünü söyleyenler vardı.
C++'da bütün sınıflar ortak bir atadan gelmedikleri için çoklu kalıtım yapılabiliyor. Diğerlerin de ise çoklu kalıtım yerine interface kullanılıyor. C++'da da interface yok ama onun işini tamamiyle abstract bir sınıf görebiliyor. C++'ı ayrı tutmak lazım.
undefined yazdı: Self nil gelmişse destructor'ın hangi objecti destroy etmesini beklersin?
Destructor'ın ait olduğu nesneyi yoketmesini beklerim. Eğer o nesne henüz yaratılmamışsa destructor'ı neye göre çağırıyorsun? Destuctor'ı çağırabiliyorsan, self nil'den farklı olmalı o zaman neden bunun kontrolünü yapma gereği duyuyorsun? İşte merak edilen bu.
undefined yazdı:Adamlar birşey yazmışsa bişey biliyorlarda yazıyorlar herhalde
O adamlar bir şey yazmışlar ama neden böyle yapmışlar? Ne bildiklerini ben de bilmek istiyorum.
Cevapla