9 Mart 2014 Pazar

exception

Not : Bu konu ile ilgili olarak Linux Sinyalleri başlıklı yazıya göz atabilirsiniz.

Exception Yakalama ve İşleme
Exception-Handling Antipatterns sayfasında bazı yanlış kullanım örnekleri var. Bunlardan bazıları ile ilgili aldığım notlar aşağıda.
Log and Throw
Bu kullanım şeklinde exception sadece loglamak amaçlı olarak yakalanıyor ve tekrar fırlatılıyor. Buradaki cevapta bu tekniğin aynı exception'ının defalarca loglanmasına yol açacağı açıklanıyor. Benzer bir cevabı burada da görebilirsiniz.

C++
exception nerede yaşar
Bu konuyu ucundan açıklayan bir cevapta, exception nesnesi fırlatıldıktan sonra runtime'da özel bir alanda yaşar diye belirtilmiş. Bu açıklama sanırım pointer olarak fırlatılmayan exception nesneleri için geçerli.

static exception nesnesi
more effective c++ Item no -13'te metod içindeki static exception nesnesi örneği var.
void someFunction()
{
    static exception ex;            // exception object
    ...
    throw &ex;                      // throw a pointer to ex
    ...
}
 
kendi exception sınıflarımız
Aşağıdaki örnekte herhangi bir sınıfın exception olarak atılabildiği gösteriliyor.

exceptionlar
C++ ile gelen tanımlı exceptionları buradan aldım.
 
std::exception sınıfı içine string alabilen bir constructor metoduna sahip değil. Bu yüzden std::logic_error veya std::runtime_error sınıfları veya bunlardan türeyen bir sınıfı kullanmak daha uygun olur. 

std::terminate()
Bir exception atıldıktan sonra eğer onu yakalayan bir catch() ifadesi yoksa C++ tarafından std::terminate() fonksiyonu çağırılır. Bu fonksiyon da direkt std::abort() fonksiyonunu çağırır . std::abort isminden de belli olduğu gibi SGABRT sinyalinin gönderilmesine sebep olur ve uygulama kapanırken çağırmak üzere atadığı atexit() vs. gibi fonksiyonları işletemeden, yani temizlik yapamadan kapanır. Eğer işletim sisteminde gerekli ayarlar yapılmışsa bir core dosyası oluşturulur.

std::abort()
std::abort() Unix dünyasındaki sinyallere değindiği için bana hep çok karışık geliyor. Aşağıda buradan bulduğum bazı notları bulabilirsiniz. Bu metod çağırılınca SIGABRT sinyali gönderiliyor. Uygulama SIGABRT sinyalini es geçmek için kod yazmışsa bile abort bir şekilde default handler'ı çağırıyor.

 Burada  da benzer bir açıklama görülebilir.  Netice de SIGABRT için signal handler atansa bile, uygulamayı kesinkes kapatıyor.

Most important signals to handle? yazıda ayrıca assert makrosu ile de std::abort() çağrıldığı için, bu sinyalin gelebileceği yazıyor.

std::set_terminate()
Eğer yakalanmamış exception'lar varsa ve de temizlik yaparak uygulamadan çıkmak istiyorsak aşağıdaki gibi bir yöntem izleyebiliriz.
std::set_terminate() metodu ile yakalanmamış exceptionları kendimiz yakalar ve std::exit() metodunu çağırırsak, programımız düzgün bir şekilde çıkar. Hem static destructorlar işletilir, hem de atexit() metodu ile atanan metotlar çağırılır ve de en önemlisi I/O streamleri boşaltılır (flush) .

std::exit()
Aşağıdaki şekli buradan aldım ve std::exit()'in nasıl çalıştığını gösteriyor. Şeklin sadece ortasındaki exit function yazan kısmına bakarsak exit handler'ların çağırıldığı ve standart I/O cleanup yapıldığını görmek mümkün. std::exit() metodunun tek kötü tarafı stack üzerinde yaratılmış olan değişkenlere ait destructor'ların çağırılmaması, yani "Destructors of variables with automatic storage durations are not called." cümlesine dikkat etmek lazım.


Aşağıdaki atexit metodunun kodu var.
int atexit (void (* __func) (void) ) {
  if (atexitCurEntries >= atexitMaxEntries){
     return ERROR;
  }
  pAtexitTable [ atexitCurEntries ].__func = __func;
  atexitCurEntries++;
  return OK;
}
std::_Exit
Bu metod fork() ile başlatılan child process'leri bitirmek için kullanılır. Böylecek atexit() ile kaydedilen metodlar çalıştırılmaz. _Exit() bir C metodudur. _exit() ise POSIX çağrısıdır.

std::quick_exit()
Eğer static desctructorları çağırmak istemiyorsak ancak I/O streamler boşaltılsın istiyorsak std::quick_exit() metodunu da kullanmak faydalı olabilir.

std::atexit()
Yeri gelmişken yukarıda bahsedilen bu metoda örnek vermek faydalı olabilir. atexit main metod içinden return ile çıkılınca veya exit() metodu çağırılınca işletilen bir metodları eklemek için kullanılır

void myexit(void)
{
  //...
}

int main()
{
  std::atexit(myexit); // exit handler ekle
}

Hiç yorum yok:

Yorum Gönder