Sobes.tech
Middle+

Provide examples of situations where a double exception might occur in the context of using the 'double exception' construct.

sobes.tech AI

Answer from AI

A double exception in C++ occurs when a new exception is thrown while another exception is being handled (inside a catch block) before the previous one has finished processing. This leads to a call to std::terminate.

Examples of situations:

  1. Throwing a new exception in a catch block:

    #include <iostream>
    #include <stdexcept>
    
    void func() {
        throw std::runtime_error("First exception");
    }
    
    int main() {
        try {
            func();
        } catch (const std::runtime_error& e) {
            std::cerr << "Caught: " << e.what() << std::endl;
            throw std::logic_error("Second exception in catch"); // Throwing a new exception
        }
        return 0;
    }
    

    Here, a new std::logic_error exception is thrown inside the catch block that handles std::runtime_error.

  2. Exception during resource cleanup in a destructor while handling another exception:

    #include <iostream>
    #include <stdexcept>
    #include <vector>
    
    struct Resource {
        ~Resource() noexcept(false) { // Destructor can throw
            std::cerr << "Resource destructor called" << std::endl;
            if (true) { // Condition that causes an exception
                throw std::runtime_error("Exception in Resource destructor");
            }
        }
    };
    
    void risky_func() {
        Resource r; // Object created, destructor may throw
        throw std::runtime_error("Exception from risky_func"); // First exception
    }
    
    int main() {
        try {
            risky_func();
        } catch (const std::runtime_error& e) {
            std::cerr << "Caught: " << e.what() << std::endl;
            // An exception may occur in the destructor 'r' while handling the first exception
        }
        return 0;
    }
    

    When risky_func throws an exception, stack unwinding occurs. During unwinding, the destructor of object r is called. If this destructor throws an exception while the first exception is being handled, a double exception occurs.

  3. Exception in an exception handler due to internal errors or calls to functions that throw:

    #include <iostream>
    #include <stdexcept>
    #include <vector>
    
    void process_error(const std::exception& e) {
        std::cerr << "Processing error: " << e.what() << std::endl;
        // This function might throw an exception under certain conditions
        if (e.what() && std::string(e.what()).length() > 20) {
             throw std::logic_error("Error processing overly long message"); // Second exception
        }
    }
    
    int main() {
        try {
            throw std::runtime_error("This is a quite long error message"); // First exception
        } catch (const std::exception& e) {
            process_error(e); // This call may throw a second exception
        }
        return 0;
    }
    

    In this case, the process_error function, called within a catch block to handle the first exception, itself throws a second exception.

In all these scenarios, because the second exception occurs before the first has finished being handled (or during stack unwinding due to the first), the C++ standard requires calling std::terminate. By default, std::terminate calls abort().