Sobes.tech
Middle+

Yapıcılar ve yıkıcılar içinde istisna fırlatma (throw exception) zorlukları hakkında konuş.

sobes.tech yapay zeka

AI'dan gelen yanıt

Yapılan bir yapıcıda istisna çağrısı, yapıcı içindeki nesnelerin veya kaynakların bir kısmı başarıyla tahsis edildiyse ve karşılık gelen yıkıcı çağrılmadıysa, kaynak sızıntılarına yol açabilir. Sızıntıları önlemek için, RAII (Kaynak Edinimi Yüklenir ve Başlatılır) kullanılması önerilir; örneğin, akıllı işaretçiler veya kaynakların serbest bırakılmasını garanti eden sarmalayıcı sınıflar kullanmak.

Yıkıcıda istisna çağrısı, tanımlanamayan davranışa yol açar. Eğer yıkıcı başka bir istisna (yığın sarmalaması) sonucu çağrılırsa ve bu istisna işlenmemişse, program std::terminate çağrısı ile sona erer. C++ standardına göre, yıkıcılar noexcept olmalıdır.

#include <iostream>
#include <memory> // std::unique_ptr için

struct Resource {
    Resource() { std::cout << "Kaynak alındı\n"; }
    ~Resource() { std::cout << "Kaynak serbest bırakıldı\n"; }
};

struct BadConstructor {
    Resource res; // Kaynak, istisna atılmadan önce tahsis edilir
    BadConstructor() {
        std::cout << "BadConstructor yapıcısı\n";
        throw std::runtime_error("Yapıcıda hata"); // İstisna atılır
        // Resource'un yıkıcısı, eğer istisna yapıcı tamamlanmadan önce atılırsa çağrılmaz
    }
    ~BadConstructor() noexcept { // Yıkıcılar noexcept olmalı
        std::cout << "BadConstructor yıkıcısı\n";
    }
};

struct GoodConstructor {
    std::unique_ptr<Resource> res; // RAII için akıllı gösterici kullanımı
    GoodConstructor() : res(std::make_unique<Resource>()) {
        std::cout << "GoodConstructor yapıcısı\n";
        // Artık, bir istisna atılırsa, unique_ptr scope'tan çıkarken Resource'un yıkıcısını garanti eder
        // throw std::runtime_error("Yapıcıda hata");
    }
    ~GoodConstructor() noexcept {
        std::cout << "GoodConstructor yıkıcısı\n";
    }
};

struct BadDestructor {
    BadDestructor() { std::cout << "BadDestructor yapıcısı\n"; }
    ~BadDestructor() {
        std::cout << "BadDestructor yıkıcısı\n";
        // Bir yıkıcıdan istisna atmak, özellikle unwind sırasında, önerilmez
        // throw std::runtime_error("Yıkıcıda hata");
    }
};

int main() {
    // Örnek, kaynak sızıntısına yol açar (RAII olmadan)
    try {
        // BadConstructor bc; // Gösterim için yorum satırı kaldırılabilir
    } catch (const std::exception& e) {
        std::cout << "Yakalanan istisna: " << e.what() << "\n";
    }

    // İyi yapıcı örneği (RAII kullanır)
    try {
        // GoodConstructor gc; // Yorum satırı kaldırılırsa, sızıntı olmaz
    } catch (const std::exception& e) {
        std::cout << "Yakalanan istisna: " << e.what() << "\n";
    }

    // Yıkıcı örneği (std::terminate ile sonuçlanabilir)
    try {
        // BadDestructor bd; // Potansiyel terminate görmek isterseniz yorum satırını kaldırın
        // throw std::runtime_error("Başka bir istisna"); // unwind'i tetikler
    } catch (const std::exception& e) {
        std::cout << "Yakalanan istisna: " << e.what() << "\n";
    }

    return 0;
}

Özet tablo:

İstisna çağrısının yapıldığı yer Potansiyel sorunlar Önerilen çözüm
Yapıcı Kaynak sızıntısı RAII kullanmak (akıllı işaretçiler, sarmalayıcılar)
Yıkıcı Tanımlanamayan davranış, std::terminate unwind sırasında Yıkıcılar noexcept olmalı, istisna atılmasından kaçınılmalı