C++ Dilinde function try block / Function Try Block ile Ctor Exception Yönetimi: Kurallar, Tuzaklar, Örnekler
- Yusuf Hançar

- Dec 29, 2025
- 4 min read
Problem: Constructor gövdesindeki try-catch, member init exception’ını yakalayamaz
class Member {
public :
Member();
Member(int);
};
class Data {
public :
Data() : mx(1) {}
private :
Member mx;
};
int main() {}
/*******************************************
AÇIKLAMA :
Data() kurucu işlevi(constructor) çalışırken önce mx(1) oluşturulur. Eğer Member(int) belirli koşulda exception throw ederse “ben Data() gövdesinde try-catch ile yakalarım” düşüncesi gelir.
Ama constructoror gövdesi ({ ... }) member initializer’lar tamamlandıktan sonra çalışır. Yani exception member initializer aşamasında fırlarsa, ctor gövdesine hiç girilmez.
Bu yüzden: “exception Data sınıfının constructor'ı içerisinde bir try-catch bloğu ile yakalanabilir mi?” → HAYIR.
------------------------------------------------------------------
CEVAP :
Data constructor gövdesindeki try-catch ile tutulamaz (catch’e hiç gelmez). Exception dışarı propagete olur; eğer dışarıda da yakalanmazsa std::terminate().
*******************************************/Yanlış Deneme: constructor gövdesine try-catch koymak (çalışmaz)
class Member {
public :
Member();
Member(int x)
{
if (x > 10)
{
throw std::runtime_error{ "exception from Member ctor\n" };
}
}
};
class Data {
public :
Data(int val) : mx(val)
{
try
{
}
catch(const std::exception& ex)
{
std::cerr << "exception caught : " << ex.what() << "\n";
}
}
private :
Member mx;
};
int main()
{
Data d(15);
}
/*******************************************
AÇIKLAMA :
Data(int val) çağrılınca önce mx(val) inşa edilir. val=15 → Member(int) exception fırlatır.
Fakat bu exception constructor gövdesinden önce oluştuğu için try { } catch { } bloğuna hiç girilmez.
Dışarıda (main’de) de catch yoksa → exception yakalanamaz → std::terminate() çağrılır.
std::terminate() default terminate handler ile tipik olarak programı sonlandırır (çoğu sistemde abort() ile biter).
İstenirse std::set_terminate() ile terminate davranışını özelleştirilebilir.
------------------------------------------------------------------
CEVAP :
Exception constructor içinde yakalanamaz. (main’de de catch olmadığı için) program std::terminate() ile biter.
*******************************************/Çözüm: Function Try Block (Constructor için “tek doğru yer”)
class Member {
public :
Member();
Member(int val)
{
if (val > 10)
{
throw std::runtime_error{ "exception from Member ctor\n" };
}
}
};
class Data {
public :
Data(int val) try : mx(val)
{
}
catch(const std::exception& ex)
{
std::cerr << "exception caught : " << ex.what() << "\n";
}
private :
Member mx;
};
int main()
{
Data d(15);
}
/*****************************
AÇIKLAMA :
1. Buradaki kritik fark şu:
-> try ctor’un tamamını kapsıyor: hem member initializer list (: mx(val)) hem de ctor gövdesi.
-> Dolayısıyla mx(val) sırasında fırlayan exception catch tarafından yakalanabilir.
2. Ama burada ikinci kritik kural devreye girer:
-> Constructor function try block catch’i biterken exception rethrow edilmek zorundadır.
-> Sen catch içinde throw; yazmasan bile, derleyici ctor için sanki throw; varmış gibi davranır (yani exception dışarı yeniden fırlatılır).
-> Çünkü ctor başarısız olduysa, obje oluşturulamaz. Obje oluşmadığı için Data d(15); tamamlanamaz; d için destructor da çalışmaz (zaten inşa yok).
Main’de yakalayan yok → rethrow edilen exception yine yakalanmaz → terminate.
-------------------------------
CEVAP :
exception caught : exception from Member ctor
terminate called after throwing an instance of 'std::runtime_error'
what(): exception from Member ctor
*****************************/Aynı örnek ama main’de yakala: propagasyon net görünür
class Member {
public :
Member();
Member(int x)
{
if (x > 10)
{
throw std::runtime_error{ "exception from Member ctor\n" };
}
}
};
class Data {
public :
Data(int val) try : mx(val)
{
}
catch(const std::exception& ex)
{
std::cerr << "exception caught : " << ex.what() << "\n";
}
private :
Member mx;
};
int main()
{
try
{
Data d(15);
}
catch(const std::exception& ex)
{
std::cerr << "in main exception caught : " << ex.what() << "\n";
}
}
/*****************************
AÇIKLAMA :
Data(int) function try block exception’ı yakalar, mesajı basar, sonra ctor tamamlanamadığı için exception rethrow edilir.
Bu sefer main’deki catch rethrow’u yakalar ve program kontrollü biçimde devam eder/sonlanır.
*****************************
CEVAP :
exception caught : exception from Member ctor
in main exception caught : exception from Member ctor
*****************************/“constructor parametresi içinde oluşan exception” function try block ile yakalanır mı?
5.1. Senaryo (Hayır)
class Error{
public :
///...
};
class Data {
public :
Data(Error) {
}
};
/*****************************
AÇIKLAMA :
Burada kritik detay: Data(Error) çağrılmadan önce, argüman olarak geçilen Error nesnesi çağrı noktasında oluşturulur.
Data d(Error{});
Bu durumda Error{} ctor’ı exception fırlatırsa, daha Data ctor’unun içine girilmeden (hatta function try block bile başlamadan) exception fırlamış olur.
Function try block, fonksiyon gövdesi + ctor init-list kapsamındadır.
Ama parametre/argüman oluşturma aşaması call site tarafındadır → yakalanamaz.
*****************************
CEVAP :
Hayır, Error argümanının oluşturulması sırasında fırlayan exception Data ctor’undaki function try block ile yakalanamaz. Ancak çağıran tarafta (main gibi) yakalanabilir.
*****************************/Function try block’ta parametre görünürlüğü (val visible)
class Data {
public :
Data(int val) try : mx(val)
{
}
catch(const std::exception& ex)
{
// auto x = val; // parametre değişkeni burda visible olur.
std::cerr << "exception caught : " << ex.what() << "\n";
}
private :
Member mx;
};
/*****************************
AÇIKLAMA :
Function try block’ta catch kısmı, aynı fonksiyonun parçası sayılır. Bu yüzden parametreler catch içinde görünür.
Bu pratikte “log bas, parametreyi yaz, telemetry ekle” gibi işlerde çok kullanışlıdır.
*****************************
CEVAP :
val catch içinde visible.
*****************************/Function try block sadece constructor değil: her fonksiyonda var (ama pratikte en çok constructor)
function try block herhangi bir fonksiyon için kullanılabilir. Ancak pratikte ctor dışında çok kritik değildir.
7.1. Örnek: catch içinde return ile toparlamak
int foo(int x)
try {
if (x > 10)
{
throw std::runtime_error{ "error\n" };
}
}
catch (const std::exception& ex)
{
std::cerr << "exception caught : " << ex.what() << "\n";
// burda return statement kullanabiliriz.
return x + 5;
}
/*****************************
AÇIKLAMA :
Bu, “fonksiyon gövdesini komple try-catch içine almak” gibi davranır ama daha kompakt bir yazımdır:
-> try bloğu fonksiyonun body’si gibidir
-> exception olursa catch’e düşer
-> catch içinde return ile “fallback” davranışı verebilirsin
Not: Normal body içinde try { ... } catch { ... } de yazılabilir; burada fark daha çok sözdizimsel ve bazı scope detaylarında ortaya çıkar.
*****************************
CEVAP :
-> x <= 10 → exception yok → fonksiyon normal akar (ama örnekte return yoksa UB/derleme uyarısı olabilir; pratikte return x; gibi bir dönüş eklenir).
-> x > 10 → catch’e girer, "exception caught : error" basar, x + 5 döner.
*****************************/Tuzak: try bloğunda tanımlanan local değişken catch’te görünmez
int foo(int x)
try {
int val{ 10 };
if (x > 10)
{
throw std::runtime_error{ "error\n" };
}
}
catch (const std::exception& ex)
{
std::cerr << "exception caught : " << ex.what() << "\n";
return x + val;
}
/*****************************
AÇIKLAMA :
val değişkeni try { ... } bloğunun scope’undadır. catch ayrı bir scope olduğu için val burada visible değildir.
Yani return x + val; derleme hatasıdır.
Bunu çözmek için:
-> val’i try öncesinde daha dış scope’a alırsın, veya
-> catch içinde ihtiyaç varsa yeniden tanımlarsın, veya
-> exception stratejisini değiştirirsin.
*****************************
CEVAP : Derleme hatası: val catch bloğunda tanımsız / görünmez.
*****************************/




Comments