Sobes.tech
Middle+

Дайте примери за ситуации, при които може да се случи повторно изключение в контекста на използването на конструкцията 'двойно изключение'.

sobes.tech AI

Отговор от AI

Двойно изключение (double exception) в C++ възниква, когато по време на обработка на изключение (вътре в блока catch) се появи ново изключение преди предишното да е приключило. Това води до извикване на std::terminate.

Примери за ситуации:

  1. Изхвърляне на ново изключение в блока catch:

    #include <iostream>
    #include <stdexcept>
    
    void func() {
        throw std::runtime_error("Първо изключение");
    }
    
    int main() {
        try {
            func();
        } catch (const std::runtime_error& e) {
            std::cerr << "Хванато: " << e.what() << std::endl;
            throw std::logic_error("Второ изключение в catch"); // Ново изключение
        }
        return 0;
    }
    

    Тук в блока catch, който обработва std::runtime_error, се хвърля ново изключение std::logic_error.

  2. Изключение при почистване на ресурси в деструктора по време на обработка на друго изключение:

    #include <iostream>
    #include <stdexcept>
    #include <vector>
    
    struct Resource {
        ~Resource() noexcept(false) { // Деструктор може да хвърли изключение
            std::cerr << "Деструктор на Resource" << std::endl;
            if (true) { // Условие, което предизвиква изключение
                throw std::runtime_error("Изключение в деструктора на Resource");
            }
        }
    };
    
    void risky_func() {
        Resource r; // Обект, деструкторът му може да хвърли
        throw std::runtime_error("Изключение от risky_func"); // Първо изключение
    }
    
    int main() {
        try {
            risky_func();
        } catch (const std::runtime_error& e) {
            std::cerr << "Хванато: " << e.what() << std::endl;
            // Тук може да възникне изключение в деструктора на 'r', докато обработваме първото
        }
        return 0;
    }
    

    Когато risky_func хвърли изключение, се извиква стекът. По време на извикването му, се извиква деструктора на r. Ако този деструктор хвърли изключение, докато се обработва първото, ще се получи двойно изключение.

  3. Изключение в обработчик на изключение поради вътрешни грешки или функции, които хвърлят изключения:

    #include <iostream>
    #include <stdexcept>
    #include <vector>
    
    void process_error(const std::exception& e) {
        std::cerr << "Обработка на грешка: " << e.what() << std::endl;
        if (e.what() && std::string(e.what()).length() > 20) {
             throw std::logic_error("Грешка при обработка на твърде дълго съобщение"); // Второ изключение
        }
    }
    
    int main() {
        try {
            throw std::runtime_error("Това е доста дълго съобщение за грешка"); // Първо изключение
        } catch (const std::exception& e) {
            process_error(e); // Този извик може да хвърли второ изключение
        }
        return 0;
    }
    

    В този случай, функцията process_error, извикана в блока catch за обработка на първото изключение, сама по себе си предизвиква второ изключение.

Във всички тези сценарии, тъй като второто изключение възниква преди завършване на обработката на първото (или по време на извикването на стека), стандартът на C++ изисква извикването на std::terminate. std::terminate по подразбиране извиква abort().