Sobes.tech
Middle+

Yıxıcıdan istisna atmaq və onu tutmaq mümkündürmü?

sobes.tech Süni İntellekt

AI-dan cavab

Mümkündür, lakin bu çox tövsiyə edilmir. Destructorun içindən istisna atılması qeyri-müəyyən davranışa səbəb ola bilər, xüsusən də destructor başqa bir istisna səbəbindən yığmanın azaldılması zamanı çağırılırsa.

#include <iostream>
#include <stdexcept>

struct Resource {
    ~Resource() {
        // Destructorun içindən istisna atmaq çox tövsiyə edilmir
        std::cerr << "Resource destructor çağırılır." << std::endl;
        // throw std::runtime_error("Resource destructorundan istisna");
    }
};

void func_with_exception() {
    Resource r;
    throw std::runtime_error("func_with_exception-dən istisna");
}

int main() {
    try {
        func_with_exception();
    } catch (const std::exception& e) {
        // Yığmanın azaldılması zamanı destructordan istisna atılırsa
        // terminate() və ya digər qeyri-müəyyən davranış baş verə bilər.
        std::cerr << "Yekunlaşdırılan istisna: " << e.what() << std::endl;
    }
    return 0;
}

Destructorlardan istisna atılmaması üçün əsas səbəblər:

  • İkiqat istisnalar: Əgər destructor başqa bir istisna zamanı çağırılırsa (məsələn, yığmanın azaldılması zamanı), yeni istisna atılması iki aktiv istisnanın eyni vaxtda mövcud olmasına səbəb olur, bu isə qeyri-müəyyən davranışdır və tez-tez std::terminate()-ə gətirib çıxarır.
  • Resursların tam təmizlənməməsi: Əgər destructorda səhv baş verərsə və istisna atılsa, həmin destructordakı digər təmizləmə əməliyyatları icra olunmaya bilər, bu isə resurs sızmalarına və digər problemlərə səbəb ola bilər.
  • Çətin səhv idarəetməsi: Destructorlardan istisna atılmasının idarə olunması proqramın məntiqini çətinləşdirir və icra axını başa düşülməsini çətinləşdirir.

C++11 və daha yeni versiyalarda destructorlar noexcept kimi qəbul edilir, yəni onlar istisna atmamalıdırlar. Əgər noexcept destructor istisna atarsa, dərhal std::terminate() çağırılır. Destructorun istisna atmasına imkan vermək üçün onu açıq şəkildə noexcept(false) kimi elan etmək lazımdır.

#include <iostream>
#include <stdexcept>

struct ResourceMayThrow {
    ~ResourceMayThrow() noexcept(false) {
        std::cerr << "ResourceMayThrow destructor çağırılır." << std::endl;
        // Bu halda istisna atıla bilər, amma hələ də tövsiyə edilmir
        // throw std::runtime_error("ResourceMayThrow destructorundan istisna");
    }
};

int main() {
    try {
        ResourceMayThrow r;
        // Əgər burada istisna baş verərsə və destructor da istisna atarsa,
        // bu, std::terminate()-ə səbəb olar.
    } catch (const std::exception& e) {
        std::cerr << "Main-də yakalanan istisna: " << e.what() << std::endl;
    }
    return 0;
}

Destructorlardan istisna atılmasının qarşısını almaq üçün aşağıdakı yanaşmaları istifadə etmək tövsiyə olunur:

  • Xəta kodu qaytarmaq: Əgər destructor xəta ilə tamamlana bilərsə, struktur xəta bayrağı saxlaya bilər və onu silməzdən sonra yoxlamaq olar.
  • Loglama: Xəta baş verdikdə, onu log faylına və ya standart xəta axınına qeyd etmək.
  • close() və ya release() funksiyasını həyata keçirmək: Resursu bağlamaq üçün ayrıca funksiya təqdim etmək və onu çağırmaq, destructor isə resursların sərbəst buraxılmasını təmin etməlidir, hətta close() çağırılmayıbsa belə.
Yanaşma Tövsiyə edilirmi? Qeydler
İstisna atmaq Xeyr std::terminate() və qeyri-müəyyən davranışa səbəb ola bilər.
Xəta kodu qaytarmaq Bəli (lazım olarsa) Objekti istifadə etdikdən sonra xəta yoxlaması tələb edir.
Loglama Bəli Debug üçün faydalıdır, proqramın işləməsini dayandırmır.
close() və ya release() funksiyası Bəli Xəta idarəsini aydınlaşdırmağa imkan verir, destructor isə təhlükəsizdir.

Ümumiyyətlə, təhlükəsiz destructor heç vaxt istisna atmayan destructordur və bu, RAII (Resource Acquisition Is Initialization) prinsipinin bir hissəsidir.