e_koca, mesajından alıntı:
Ne demek istediginizi anlamadim, biraz daha acarmisiniz?
O ilkeleri çok hızlı bir şekilde yazmıştım... Tabii ki açıklamak gerek... 
Bir sınıfın üye işlevi içindeyiz diyelim. Bu nesnenin üyelerinde değişiklik yapmamız gerekiyor... İlkenin söylediği şu: önce hata atma olasılığı olan işlemleri yap, ancak onlar başarılı olur da hata atılmazsa nesnenin üyelerini değiştir.
Bunun en güzel örneği atama işlecidir. Atama işleci iki işlemden oluşur: eldeki kaynakları geri veri, yeni kaynakları kopyala. Ve yanlış olarak şöyle yazılabilir:
Kod:
Foo & Foo::operator= (const Foo & sagdaki)
{
if (this != &sagdaki) {
kaynaklari_geri_ver(); // <-- YANLIS
kaynaklari_kopyala(sagdaki);
}
return *this;
}
Bunun nedeni, kaynakların sağdaki nesneden kopyalanması sırasında hata atılabileceği, ve bu yüzden bu nesnenin artık kaynaksız ve tutarsız bir durumda kalabileceğidir.
Atama işleci, bu ilkenin söylediği gibi yazılırsa, atama işleminin iki adımının ters sırada yapılmaları gerekir: önce kopyala, sonra kaynakları geri ver:
Kod:
Foo & Foo::operator= (const Foo & sagdaki)
{
Foo gecici(sagdaki); // <-- kopyala
// hata atmayan 'swap' islemi:
this->degis_tokus_et(gecici);
return *this;
} // <-- eski kaynaklar bu noktada, gecici sonlandirilirken geri verilir
Burda hatayi yakalamaktanmi, yoksa islemektenmi bahsettiniz ?
"hataları hiçbir zaman sonraya bırakma; sınıfları tasarlarken de akılda olsun" ilkesi, zaten yazılmış bir programın hatalar karşısında doğru çalışacak şekilde düzeltilmesinin zor olacağını söyler. Hatalar (exception), tasarımın başından akılda tutulması gereken bir düzenektir.
Bunun bir örneği, veri yapılarından 'stack'tir. Bu veri yapısının klasik arayüzünde iki işlev bulunur:
- push: topluluğa yeni eleman ekler
- pop: topluluğun tepesindeki çıkartır ve bize döndürür
O arayüz hatalara uygun değildir. Çünkü pop'un, çıkarttığı elemanı *kopyalayarak* döndürmesi gerekir. (Bunun örnek bir kodu yukarıda bağlantısını verdiğim sunuda var)
Eğer o kopyalama işlemi hata atarsa, veri yapısından bir eleman eksilmiş, ama hiç kimse o elemanı görememiş olur.
'stack'in hatalara uygun arayüzünde üç üye olması gerekir:
- push: topluluğa yeni eleman ekler
- top: topluluğun tepesindekine erişim sağlar
- pop: topluluğun tepesindekini çıkartır
Görevlerin böyle bölünmüş olmaları, bu veri yapısını hatalar karşısında doğru çalışmasını sağlar. (Daha önce "cohesion" sözcüğünü yanlış yerde kullandım; "cohesion" bu kavrama uygundur.)
Mesela siralama islemi yapan bir isleve, tamam sen siralamani yap ayni zamanda en buyuk sayiyida bize dondur dedigimiz zaman.
Belki daha iyisi, sıralama ile en büyüğe erişimi birbirlerinden ayırmaktır.
Aslında en büyüğüne erişim sağlama işleminde hata atacak bir şey yoksa, belki o da çalışır. Örneğin dönüş türü bir referans ise, bir sorun yoktur. 'stack'te ise referans olamaz, çünkü veri yapısından çıkartılmıştır. Orada kopyalanması şarttır.
Mantikli bir ornek degil ama ogrenmek acisindan soruyorum, hata yakalama acisindan bunun sakicasi ne ? Siralamayi yapamadigin icinmi bir hata nesnesi firlatildi yoksa en buyugunu donduremedigi icinmi bir hata nesnesi firlatildi ikileminde biraktigi icinmi ?
Hayır, o ikilemden bahsetmiyordum. Çünkü atılan hatalar farklı türlerden olabilirler. İşlev duruma göre farklı hata atar, yakalayanlar da özellikle onlardan birisini yakalayabilirler. Veya, _Onk@_'ya yazdığım gibi, her hatayı yakalamak için sıradüzenin en tepesindeki std::exception hatasını yakalarlar.
Ali
Bookmarks