ProgramlamaC++ Backend Geliştirici

C++'da istisna sistemi (exceptions) nasıl çalışır, diğer dillerden farkı nedir? Endüstriyel uygulamalarda istisna işlemlerini nasıl doğru bir şekilde tasarlamalıyız?

Hintsage yapay zeka asistanı ile mülakatları geçin

Cevap

C++'da istisna sistemi, try-catch mekanizmasına ve throw anahtar kelimesine dayanmaktadır. İstisnai bir durum (örneğin, kaynak hatası, invariant ihlali) meydana geldiğinde, try bloğu içinde istisna throw operatörü ile başlatılır (fırlatılır). Uygun işleyiciyi bulma işlemi (catch) yığının üstünden ilk eşleşen tür bulunana kadar devam eder.

Önemli detaylar:

  • Java veya C#'dan farklı olarak, C++'da istisnalar her türde olabilir (genellikle std::exception sınıfından türetilmiş bir sınıf).
  • C++'da zorunlu istisna spesifikasyonu yoktur (Java'daki checked exceptions gibi), bunun yerine C++11 ve sonrası için noexcept belirticisi getirilmiştir.
  • İstisna fırlatıldığında, fırlatma noktası ile işleme noktası arasındaki tüm yığındaki nesnelerin yok edicileri çağrılır — RAII'yi desteklemek önemlidir.

Tasarım:

  • Sadece "beklenmeyen" hata istisnalarını fırlatın, diğer durumlar için return kodu kullanın.
  • Sabit referans ile yakalayın — catch(const std::exception& e).
  • GNU, fırlatma işlemi için kopyalanabilir nesneleri, değil işaretçileri önerir (yığın belleğini kullanmaktan kaçının).

Kod örneği:

#include <iostream> #include <stdexcept> void mayFail(bool fail) { if (fail) throw std::runtime_error("İşlem hatası"); } int main() { try { mayFail(true); } catch (const std::exception& ex) { std::cout << "Yakalanan istisna: " << ex.what() << std::endl; } }

Aldatıcı soru

Eğer bir istisna, başka bir istisna yukarı doğru iletilirken yok ediciden fırlatılırsa ne olacaktır?

Cevap: Program std::terminate() ile aniden sonlanır, çünkü istisna işlenirken yeni bir istisna (double exception) fırlatılmasına izin verilmez, aksi halde yığın açılımı bozulur.

Örnek:

struct CrashOnDestruct { ~CrashOnDestruct() noexcept(false) { throw std::runtime_error("Yok edicide hata!"); } }; void func() { CrashOnDestruct obj; throw std::logic_error("Hata işleme"); } int main() { try { func(); } catch (...) { } } // std::terminate() ile sonlanır

Konu ile ilgili birçok hatanın örnekleri


Hikaye

Büyük bir finansal uygulamada istisnalar, bir veritabanı sarmalayıcı sınıfının yok edicisinden fırlatılıyordu. Hata meydana geldiğinde ana işlemlerden biri bir istisna başlatıyordu, unwind çıkışında yok edici çağrılıyordu ve o da hata fırlatıyordu. Tüm uygulama, kullanıcıların işlerini kaybetmesiyle aniden sonlanıyordu. Geliştiricilerin, yok edicilerde throw yerine log kaydı ve düzgün işleme geçirmesi gerekiyordu.


Hikaye

Mikro hizmet, istisnaları türüne göre işliyordu: catch(std::exception). Bir iş parçacığı, kullanıcı türünde istisnalar fırlatıyordu (std::exception'dan türemiyordu). Bu tür hatalar yakalanmadı ve beklenmedik bir bağlantı kopması ile bellek sızıntısına neden oldu.


Hikaye

Konteynerlerin taşıma yöntemlerinde noexcept spesifikatorünün eksikliği, standart kütüphanenin hızlı hareket kopyası yerine yavaş kopyalamayı kullanmasıyla sonuçlandı; önemli bir performans kaybı sadece yük testlerinde ortaya çıkarıldı.