Sobes.tech
Middle+

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:

  1. 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 catch que trata std::runtime_error, uma nova exceção std::logic_error é lançada.

  2. 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_func lança uma exceção, a pilha é desempilhada. Durante esse processo, o destruidor do objeto r é chamado. Se esse destruidor lançar uma exceção enquanto a primeira ainda está sendo tratada, ocorre uma exceção dupla.

  3. 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 bloco catch para 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().