C++'da dinamik nesnelerin yaşamları new ile başlar, delete ile biter.
new'ün iki işi vardır: nesne için bellek ayırmak ve o belleği nesnenin üyeleri haline getirmek (yani nesneyi kurmak).
delete'in de bunun tersi iki işi vardır: nesnenin sonlandırıcı işlevini çalıştırmak, ve nesnenin belleğini geri vermek.
Bunların ikisi de D'de var. Sınıf nesneleri zaten new ile kurulmak zorundalar, ve new D'de de aynı şekilde çalışıyor. delete ise şaşırtıcı olarak emekliye ayrılmak üzere! :)
Bunun nedeni, D'de çöp toplayıcı olması ve belleğin geri verilmesinin çöp toplayıcının çok temel bir işi olmasıymış. delete'in iki işinden birincisi, yani nesnenin sonlandırıcı işlevinin çağrılması ise 'clear' ile sağlanıyor. Yani belleğin geri verilmesine karışmıyoruz ama çok gereken durumlarda, sonlandırıcı işlevi kendimiz çağırabiliyoruz.
Bir örnek:
import std.stdio;
class Sınıf
{
int i;
this(int i)
{
this.i = i;
writeln(i, " kuruldu");
}
~this()
{
writeln(i, " sonlandırıldı");
}
}
void main()
{
writeln("main'e girildi");
foreach (i; 1 .. 5) {
auto nesne = new Sınıf(i);
// ... nesneyle ilgili işlemler ...
}
writeln("main'den çıkılıyor");
}
Yukarıdaki döngüde oluşturulan nesnelerin sonlandırıcıları normalde main'den çıkıldıktan sonra çağrılıyor:
main'e girildi
1 kuruldu
2 kuruldu
3 kuruldu
4 kuruldu
main'den çıkılıyor
4 sonlandırıldı
3 sonlandırıldı
2 sonlandırıldı
1 sonlandırıldı
Hatta, bazı programlarda hiç çağrılmayabiliyor bile. O yüzden belki de sizin ortamınızda "sonlandırıldı" satırlarını göremeyebilirsiniz.
Bazı özel durumlarda, sonlandırıcıyı kendimiz çağırmak istersek clear'i kullanıyoruz:
foreach (i; 1 .. 5) {
auto nesne = new Sınıf(i);
// ... nesneyle ilgili işlemler ...
clear(nesne);
}
Çıktının baş tarafı beklediğimiz gibi oluyor, ama garip bir şekilde, sonda hiç oluşturmadığımız 0 numaralı nesnelerin de sonlandırıldığını görüyoruz:
main'e girildi
1 kuruldu
1 sonlandırıldı
2 kuruldu
2 sonlandırıldı
3 kuruldu
3 sonlandırıldı
4 kuruldu
4 sonlandırıldı
main'den çıkılıyor
0 sonlandırıldı
0 sonlandırıldı
0 sonlandırıldı
0 sonlandırıldı
Bunun nedeni, clear'in nesneyi yok etmemesi, ama o türün '.init' durumuna sokmasıymış. Yani nesne sonlandırılıyor, ama yine de boş bir durumda bulunuyor. Daha sonradan çöp toplayıcı karar verdiğinde, aynı nesneyi bir kere daha sonlandırıyor.
İlginç... :)
Tabii aslında nesnenin hemen döngü sonunda sonlanmasını istesek, 'scope' anahtar sözcüğünden de yararlanabilirdik, ve belki de daha doğru olurdu:
foreach (i; 1 .. 5) {
scope auto nesne = new Sınıf(i);
// ... nesneyle ilgili işlemler ...
}
O durumda çıktıda 0 numaralı sonlandırmaları görmezdik:
main'e girildi
1 kuruldu
1 sonlandırıldı
2 kuruldu
2 sonlandırıldı
3 kuruldu
3 sonlandırıldı
4 kuruldu
4 sonlandırıldı
main'den çıkılıyor
O da her duruma uygun değildir; çünkü scope nesnelerin o döngünün dışında yaşamaları olanaksızdır. Bence kurallar şöyle olmalı:
-
Eğer özel bir nedeni yoksa nesnenin sonlanması ile ilgili hiçbir şey yapmamalı
-
Eğer sonlandırıcının nesneye gerek kalmadığı zaman hemen çağrılması gerekiyorsa, öncelikle 'scope' düşünülmeli
-
Eğer olmuyorsa, nesnenin işi bittiğinde 'clear' çağrılmalı
Ali
--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]