How do I make a call to what() on std::exception_ptr

前端 未结 4 1758
别那么骄傲
别那么骄傲 2020-12-28 13:26

This is the code I have.

try
{
// code throws potentially unknown exception
}
catch (...)
{
    std::exception_ptr eptr =  std::current_exception();
             


        
4条回答
  •  粉色の甜心
    2020-12-28 14:15

    // then what ?

    here is what:

    #include 
    #include 
    #include 
    #include 
    
    std::string what(const std::exception_ptr &eptr = std::current_exception())
    {
        if (!eptr) { throw std::bad_exception(); }
    
        try { std::rethrow_exception(eptr); }
        catch (const std::exception &e) { return e.what()   ; }
        catch (const std::string    &e) { return e          ; }
        catch (const char           *e) { return e          ; }
        catch (...)                     { return "who knows"; }
    }
    
    int main()
    {
        try { throw std::runtime_error("it's success!"); }
        catch (...) { std::cerr << "Here is WHAT happened: " << what() << std::endl;  }
    
        try { throw 42; } catch (...) { std::cerr << "and now what: " << what() << std::endl;  }
    }
    

    what it prints:

    Here is WHAT happened: it's success!
    and now what: who knows
    

    http://coliru.stacked-crooked.com/a/1851d2ab9faa3a24

    so this allows to get what in the catch-all clause.

    but what if exception is nested??? here is what:

    std::string what(const std::exception_ptr &eptr = std::current_exception());
    
    template 
    std::string nested_what(const T &e)
    {
        try         { std::rethrow_if_nested(e); }
        catch (...) { return " (" + what(std::current_exception()) + ")"; }
        return {};
    }
    
    std::string what(const std::exception_ptr &eptr)
    {
        if (!eptr) { throw std::bad_exception(); }
    
        try { std::rethrow_exception(eptr); }
        catch (const std::exception &e) { return e.what() + nested_what(e); }
        catch (const std::string    &e) { return e          ; }
        catch (const char           *e) { return e          ; }
        catch (...)                     { return "who knows"; }
    }
    

    using example from here:

    #include 
    
    ...
    
    // sample function that catches an exception and wraps it in a nested exception
    void open_file(const std::string& s)
    {
        try {
            std::ifstream file(s);
            file.exceptions(std::ios_base::failbit);
        } catch(...) {
            std::throw_with_nested( std::runtime_error("Couldn't open " + s) );
        }
    }
    
    // sample function that catches an exception and wraps it in a nested exception
    void run()
    {
        try {
            open_file("nonexistent.file");
        } catch(...) {
            std::throw_with_nested( std::runtime_error("run() failed") );
        }
    }
    
    int main()
    {
        try { throw std::runtime_error("success!"); }
        catch (...) { std::cerr << "Here is WHAT happened: \"" << what() << '\"' << std::endl;  }
    
        try { run(); }
        catch (...) { std::cerr << "what happened for run: \""  << what() << '\"' << std::endl;  }
    }
    

    what is printed:

    Here is WHAT happened: "success!"
    what happened for run: "run() failed (Couldn't open nonexistent.file (basic_ios::clear))"
    

    http://coliru.stacked-crooked.com/a/901a0c19297f02b5

    but what if recursion too deep? what if stackoverflow? optimized what:

    #include 
    
    template 
    std::exception_ptr get_nested(const T &e)
    {
        try
        {
            auto &nested = dynamic_cast(e);
            return nested.nested_ptr();
        }
        catch (const std::bad_cast &)
            { return nullptr; }
    }
    
    #if 0 // alternative get_nested
        std::exception_ptr get_nested()
        {
            try                                    { throw                ; }
            catch (const std::nested_exception &e) { return e.nested_ptr(); }
            catch (...)                            { return nullptr       ; }
        }
    #endif
    
    std::string what(std::exception_ptr eptr = std::current_exception())
    {
        if (!eptr) { throw std::bad_exception(); }
    
        std::string whaaat;
        std::size_t num_nested = 0;
        next:
        {
            try
            {
                std::exception_ptr yeptr;
                std::swap(eptr, yeptr);
                std::rethrow_exception(yeptr);
            }
            catch (const std::exception &e) { whaaat += e.what()   ; eptr = get_nested(e); }
            catch (const std::string    &e) { whaaat += e          ; }
            catch (const char           *e) { whaaat += e          ; }
            catch (...)                     { whaaat += "who knows"; }
    
            if (eptr) { whaaat += " ("; num_nested++; goto next; }
        }
        whaaat += std::string(num_nested, ')');
        return whaaat;
    }
    

    the same whats:

    Here is WHAT happened: "success!"
    here is what: "run() failed (Couldn't open nonexistent.file (basic_ios::clear))"
    

    http://coliru.stacked-crooked.com/a/32ec5af5b1d43453

    UPD

    The similar functionality can be implemented in C++03 by using a trick that allows to rethrow current exception outside of catch block: https://stackoverflow.com/a/3641809/5447906

提交回复
热议问题