Forneça exemplos de situações em que pode ocorrer uma reexceção no contexto do uso da construção 'dupla exceção'.
sobes.tech IA
Resposta da IA
A exceção dupla em C++ ocorre quando, durante o tratamento de uma exceção (dentro do bloco catch), uma nova exceção é lançada antes de o tratamento anterior ser concluído. Isso leva à chamada de std::terminate.
Exemplos de situações:
-
Lançar uma nova exceção dentro de um bloco
catch:#include <iostream> #include <stdexcept> void func() { throw std::runtime_error("Primeira exceção"); } int main() { try { func(); } catch (const std::runtime_error& e) { std::cerr << "Capturado: " << e.what() << std::endl; throw std::logic_error("Segunda exceção no catch"); // Nova exceção } return 0; }Aqui, no bloco
catchque tratastd::runtime_error, uma nova exceçãostd::logic_erroré lançada. -
Exceção durante a limpeza de recursos num destruidor no contexto do tratamento de outra exceção:
#include <iostream> #include <stdexcept> #include <vector> struct Resource { ~Resource() noexcept(false) { // O destruidor pode lançar uma exceção std::cerr << "Destruidor de Resource chamado" << std::endl; if (true) { // Condição que provoca a exceção throw std::runtime_error("Exceção no destruidor de Resource"); } } }; void risky_func() { Resource r; // Cria um objeto cujo destruidor pode lançar throw std::runtime_error("Exceção em risky_func"); // Primeira exceção } int main() { try { risky_func(); } catch (const std::runtime_error& e) { std::cerr << "Capturado: " << e.what() << std::endl; // Aqui pode ocorrer uma exceção no destruidor 'r' enquanto tratamos a primeira exceção } return 0; }Quando
risky_funclança uma exceção, a pilha é desempilhada. Durante esse processo, o destruidor do objetoré chamado. Se esse destruidor lançar uma exceção enquanto a primeira ainda está sendo tratada, ocorre uma exceção dupla. -
Exceção no manipulador de exceções devido a erros internos ou chamadas de funções que lançam exceções:
#include <iostream> #include <stdexcept> #include <vector> void process_error(const std::exception& e) { std::cerr << "Processando erro: " << e.what() << std::endl; // Suponha que esta função possa lançar uma exceção sob certas condições if (e.what() && std::string(e.what()).length() > 20) { throw std::logic_error("Erro ao processar mensagem demasiado longa"); // Segunda exceção } } int main() { try { throw std::runtime_error("Esta é uma mensagem de erro bastante longa"); // Primeira exceção } catch (const std::exception& e) { process_error(e); // Esta chamada pode lançar uma segunda exceção } return 0; }Nesse caso, a função
process_error, chamada no blococatchpara tratar a primeira exceção, inicia uma segunda exceção.
Em todos esses cenários, uma vez que a segunda exceção ocorre antes de a primeira ser completamente tratada (ou durante a desempilhamento devido à primeira), o padrão C++ exige a chamada de std::terminate. std::terminate por padrão chama abort().