Sobes.tech
Middle+

İstisna (exception) çağrılırken neden yıkıcılar (destructors) çağrılmaz?

sobes.tech yapay zeka

AI'dan gelen yanıt

Otomatik ömürlü yerel nesnelerin yıkıcıları, eğer yapıcıda istisna atılırsa ve nesne tamamen inşa edilmemişse çağrılmaz.

Ayrıca, aşağıdaki durumlar için yıkıcılar çağrılmaz:

  • Küresel veya statik ömürlü nesneler.
  • Standart mekanizmalarla yönetilmeyen ham bellek üzerindeki nesneler (örneğin, malloc ile tahsis edilip serbest bırakılmayanlar).
  • Kaçan akıllı göstericilere işaret eden nesneler.
  • noexcept(false) olarak işaretlenmiş ve yıkıcıları kendileri istisna atan nesneler. Bu durumda, genellikle program std::terminate ile sonlandırılır.

Konstrüktörde çağrılmayan yıkıcı örneği:

#include <iostream>
#include <stdexcept>

class Resource {
public:
    Resource() {
        std::cout << "Kaynak alındı" << std::endl;
    }
    ~Resource() {
        std::cout << "Kaynak serbest bırakıldı" << std::endl;
    }
};

class MyClass {
public:
    Resource res1; // Bu yıkıcı, MyClass yapıcısında istisna atılırsa çağrılır
    // Resource res2; // Burada istisna atılırsa, res2 inşa edilmez

    MyClass() {
        // res1 zaten inşa edildi
        std::cout << "MyClass yapıcısı" << std::endl;
        throw std::runtime_error("MyClass yapıcı hatası");
        // res2 = Resource(); // Bu nesne inşa edilmez, eğer yukarıda istisna atılırsa
    }
    ~MyClass() {
        std::cout << "MyClass yıkıcısı" << std::endl;
    }
};

int main() {
    try {
        MyClass obj; // Burada istisna oluşur
    } catch (const std::runtime_error& e) {
        std::cerr << "Yakalanan istisna: " << e.what() << std::endl;
    }
    return 0;
}

Bu örnekte, MyClass'ın yıkıcısı çağrılmaz çünkü MyClass yapıcısı başarıyla tamamlanmamıştır. Ancak, res1'in yıkıcısı (MyClass'in parçası) çağrılır çünkü res1, istisna atılmadan önce başarıyla inşa edilmiştir.

İç içe geçmiş istisna durumunda yıkıcı çağrısı örneği:

#include <iostream>
#include <stdexcept>

class BadDestructor {
public:
    BadDestructor() {
        std::cout << "BadDestructor yapıcısı" << std::endl;
    }
    ~BadDestructor() noexcept(false) {
        std::cout << "BadDestructor yıkıcısı" << std::endl;
        throw std::runtime_error("Yıkıcıda hata"); // İstisna atar
    }
};

void foo() {
    BadDestructor obj;
    throw std::runtime_error("foo'da istisna");
}

int main() {
    try {
        foo();
    } catch (const std::runtime_error& e) {
        std::cerr << "Yakalanan istisna: " << e.what() << std::endl;
    }
    // std::terminate, bu noktadan önce çağrılır
    return 0;
}

Bu durumda, foo içinde istisna atıldığında, yığın temizleme başlar. BadDestructor'ın yıkıcısı çağrılır. Bu yıkıcı, bir istisna attığı için (noexcept(false) izin verir), mevcut istisna sırasında ikinci bir istisna oluşur. C++ standardına göre, bu durumda std::terminate çağrılır ve program sona erer. Yığındaki diğer nesnelerin yıkıcıları (varsa foo'dan önceki nesneler) çağrılmayabilir.