Uveďte príklady situácií, kedy môže dôjsť k opätovnému výnimke v kontexte použitia konštrukcie 'dvojitá výnimka'.
sobes.tech AI
Odpoveď od AI
Dvojitá výnimka (double exception) v C++ nastáva, keď počas spracovania výnimky (napríklad v bloku catch) vznikne nová výnimka skôr, než je ukončené spracovanie predchádzajúcej. To vedie k volaniu std::terminate.
Príklady takýchto situácií:
-
Vyhodenie novej výnimky v bloku
catch:#include <iostream> #include <stdexcept> void func() { throw std::runtime_error("Prvá výnimka"); } int main() { try { func(); } catch (const std::runtime_error& e) { std::cerr << "Chytené: " << e.what() << std::endl; throw std::logic_error("Druhá výnimka v catch"); // Nová výnimka } return 0; }Tu v bloku
catch, ktorý spracovávastd::runtime_error, je vyhodená novástd::logic_error. -
Výnimka počas čistenia zdrojov v destruktore počas spracovania inej výnimky:
#include <iostream> #include <stdexcept> #include <vector> struct Resource { ~Resource() noexcept(false) { // Destruktor môže vyvolať výnimku std::cerr << "Volanie destruktora Resource" << std::endl; if (true) { // Podmienka, ktorá spôsobí výnimku throw std::runtime_error("Výnimka v destruktore Resource"); } } }; void risky_func() { Resource r; // Objekt, destruktor ktorého môže vyvolať výnimku throw std::runtime_error("Výnimka z risky_func"); // Prvá výnimka } int main() { try { risky_func(); } catch (const std::runtime_error& e) { std::cerr << "Chytené: " << e.what() << std::endl; // Tu môže nastať výnimka v destruktore 'r', zatiaľ čo spracovávame prvú } return 0; }Keď
risky_funcvyhodí výnimku, dochádza k odvíjaniu zásobníka. Počas odvíjania je volaný destruktor objektur. Ak tento destruktor sám vyvolá výnimku, zatiaľ čo spracovávame prvú výnimku, vznikne dvojitá výnimka. -
Výnimka v obsluhe výnimky kvôli interným chybám alebo volaniam funkcií, ktoré vyvolávajú výnimky:
#include <iostream> #include <stdexcept> #include <vector> void process_error(const std::exception& e) { std::cerr << "Spracovanie chyby: " << e.what() << std::endl; if (e.what() && std::string(e.what()).length() > 20) { throw std::logic_error("Chyba pri spracovaní príliš dlhého hlásenia"); // Druhá výnimka } } int main() { try { throw std::runtime_error("Toto je dosť dlhé hlásenie o chybe"); // Prvá výnimka } catch (const std::exception& e) { process_error(e); // Tento volanie môže vyvolať druhé výnimka } return 0; }V tomto prípade funkcia
process_error, ktorá je volaná v blokucatchna spracovanie prvej výnimky, sama spôsobí druhú výnimku.
Vo všetkých týchto scenároch, pretože druhá výnimka vznikne pred dokončením spracovania prvej (alebo počas odvíjania zásobníka kvôli prvej), štandard C++ vyžaduje volanie std::terminate. std::terminate vo výchozom nastavení volá abort().