Дайте примери за ситуации, при които може да се случи повторно изключение в контекста на използването на конструкцията 'двойно изключение'.
sobes.tech AI
Отговор от AI
Двойно изключение (double exception) в C++ възниква, когато по време на обработка на изключение (вътре в блока catch) се появи ново изключение преди предишното да е приключило. Това води до извикване на std::terminate.
Примери за ситуации:
-
Изхвърляне на ново изключение в блока
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. -
Изключение при почистване на ресурси в деструктора по време на обработка на друго изключение:
#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. Ако този деструктор хвърли изключение, докато се обработва първото, ще се получи двойно изключение. -
Изключение в обработчик на изключение поради вътрешни грешки или функции, които хвърлят изключения:
#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().