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

前端 未结 4 1742
别那么骄傲
别那么骄傲 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:04
    try
    {
       std::rethrow_exception(eptr);
    }
    catch (const std::exception& e)
    {
       std::cerr << e.what() << std::endl;
    }
    

    http://en.cppreference.com/w/cpp/error/exception_ptr

    0 讨论(0)
  • 2020-12-28 14:05

    Using std::current_exception seems a bit over the top in your case, since you don't seem to want to store or copy the std::exception_ptr for later processing (which is its only intent, it doesn't help with gaining additional information about an unknown exception in any way). If you just want to treat the case of a std::exception, what about the simple:

    try
    {
        // code throws potentially unknown exception
    }
    catch (const std::exception &e)
    {
        std::cerr << e.what() << '\n';  // or whatever
    }
    catch (...)
    {
        // well ok, still unknown what to do now, 
        // but a std::exception_ptr doesn't help the situation either.
        std::cerr << "unknown exception\n";
    }
    
    0 讨论(0)
  • 2020-12-28 14:07

    Not the best solution in my opinion but seems to work.

    try
    {
    // code throws potentially unknown exception
    }
    catch (const std::exception& e)
    {
       std::cerr << e.what() << std::endl;
    }
    catch (...)
    {
        std::exception_ptr eptr =  std::current_exception();
            // then what ?
        LogUnknownException();
    }
    

    Thanks to ForEveR for the initial solution but I am not sure if I want to throw again within the catch block.

    0 讨论(0)
  • 2020-12-28 14:15

    // then what ?

    here is what:

    #include <exception>
    #include <stdexcept>
    #include <iostream>
    #include <string>
    
    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 <typename T>
    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 <fstream>
    
    ...
    
    // 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 <typeinfo>
    
    template <typename T>
    std::exception_ptr get_nested(const T &e)
    {
        try
        {
            auto &nested = dynamic_cast<const std::nested_exception&>(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

    0 讨论(0)
提交回复
热议问题