Sobes.tech
Middle+

Adjon példákat olyan helyzetekre, amikor a 'kettős kivétel' konstrukció használata során ismételt kivétel fordulhat elő.

sobes.tech MI

Válasz az MI-től

A C++-ban a dupla kivétel (double exception) akkor fordul elő, amikor egy kivételkezelés (például a catch blokkban) során egy új kivétel keletkezik, mielőtt az előző kivétel befejeződne. Ez a std::terminate hívásához vezet.

Példák ilyen helyzetekre:

  1. Új kivétel dobása a catch blokkban:

    #include <iostream>
    #include <stdexcept>
    
    void func() {
        throw std::runtime_error("Első kivétel");
    }
    
    int main() {
        try {
            func();
        } catch (const std::runtime_error& e) {
            std::cerr << "Elfogva: " << e.what() << std::endl;
            throw std::logic_error("Második kivétel a catch-ben"); // Új kivétel keletkezik
        }
        return 0;
    }
    

    Itt a catch blokkban, amely a std::runtime_error-t kezeli, egy új std::logic_error kivétel dobódik.

  2. Erőforrások tisztítása során a destruktorban keletkező kivétel:

    #include <iostream>
    #include <stdexcept>
    #include <vector>
    
    struct Resource {
        ~Resource() noexcept(false) { // A destruktor kiválthat kivételt
            std::cerr << "Resource destruktor hívása" << std::endl;
            if (true) { // Feltétel, ami kivételt okoz
                throw std::runtime_error("Kivétel a Resource destruktorában");
            }
        }
    };
    
    void risky_func() {
        Resource r; // Objektum létrehozva, destruktor kivételt dobhat
        throw std::runtime_error("Kockázatos függvény kivétele"); // Első kivétel
    }
    
    int main() {
        try {
            risky_func();
        } catch (const std::runtime_error& e) {
            std::cerr << "Elfogva: " << e.what() << std::endl;
            // Itt kivétel keletkezhet a destruktorban, miközben az első kivételt kezeljük
        }
        return 0;
    }
    

    Amikor a risky_func kivételt dob, a verem lefele indul. A lefele haladás során meghívódik a r objektum destruktora, és ha az destruktor kivételt dob, miközben az első kivételt kezeljük, dupla kivétel keletkezik.

  3. Kivétel a kivételkezelőben belső hibák vagy kivételt dobó függvények miatt:

    #include <iostream>
    #include <stdexcept>
    #include <vector>
    
    void process_error(const std::exception& e) {
        std::cerr << "Hiba feldolgozása: " << e.what() << std::endl;
        if (e.what() && std::string(e.what()).length() > 20) {
             throw std::logic_error("Hiba túl hosszú üzenet feldolgozásakor"); // Második kivétel
        }
    }
    
    int main() {
        try {
            throw std::runtime_error("Ez egy elég hosszú hibaüzenet"); // Első kivétel
        } catch (const std::exception& e) {
            process_error(e); // Ez a hívás második kivételt dobhat
        }
        return 0;
    }
    

    Ebben az esetben a process_error függvény, amelyet az első kivétel kezelésére hívunk, maga is második kivételt okoz.

Mindezekben az esetekben, mivel a második kivétel az első befejezése előtt vagy közben keletkezik, a C++ szabvány a std::terminate hívását írja elő. A std::terminate alapértelmezés szerint az abort()-ot hívja.