有没有办法获得至少为catch(...)的一些信息?

时间:2009-06-28 17:13:56

标签: c++ exception exception-handling

有没有办法在这里获得至少一些信息?

...
catch(...)
{
  std::cerr << "Unhandled exception" << std::endl;
}

我将这作为我所有代码的最后手段。让它崩溃会更好吗,因为那时我至少可以得到崩溃报告?

5 个答案:

答案 0 :(得分:9)

不,没有办法。尝试使所有异常类派生自一个类,如std::exception,然后捕获那个。

但是,您可以重新抛出嵌套的try,以试图找出类型。但是你可以使用之前的catch子句(并且 ... 仅作为后退)。

答案 1 :(得分:4)

您可以使用gdb或其他调试器执行此操作。告诉调试器在抛出任何异常时停止(在gdb中,命令是热闹的catch throw)。然后,您不仅会看到异常的类型,还会看到它的确切位置。

另一个想法是注释掉catch (...)并让你的运行时终止你的应用程序,并希望告诉你更多关于异常的信息。

一旦你弄清楚异常是什么,你应该尝试用从std::exception派生的东西替换或扩充它。完全不得不catch (...)

如果您使用GCC或Clang,您还可以尝试__cxa_current_exception_type()->name()获取当前例外类型的名称。

答案 2 :(得分:1)

是的,但它有多大用处可以辩论:

#include <exception>
#include <iostream>
using namespace std;

int f() {
    throw "message";
}

int main() {
    try {
        f();
    }
    catch ( ... ) {
        try {
            throw;
        }
        catch( const char *  s ) {
            cout << "caught " << s << endl;
        }
    }
}

实际上要回答你的问题,恕我直言,你应该总是有一个问题(...) 代码的顶级,当您的应用程序中出现意外异常时,以应用程序手册完整记录的方式终止(或以其他方式处理)。

答案 3 :(得分:0)

我相信你应该捕获(...),如果你在这一点上有一个合理的行动方案并希望应用程序继续运行。

请注意,您不必为了生成崩溃报告而崩溃。有用于生成小型转储的API,您可以在SEH处理程序中执行此操作。

答案 4 :(得分:0)

这是我在一个项目中使用的方法。它涉及重新抛出,直到异常类型与已知异常列表匹配,然后在匹配时调度某些操作(在这种情况下只返回一些字符串信息,但它也可以调用已注册的函数对象)。

如果您愿意,可以将此想法扩展到异常类型的动态注册表中,您必须注意的事项是确保列表是从大多数派生到最少派生的顺序(需要批次) 在注册期间重新投掷和捕获!)

#include <iostream>
#include <stdexcept>
#include <exception>
#include <typeinfo>
#include <system_error>

namespace detail {
    // a function which compares the current exception against a list of exception types terminated
    // with a void type
    // if a match is made, return the exception (mangled) class name and the what() string.
    // note that base classes will be caught if the actual class is not mentioned in the list
    // and the list must be in the order of most-derived to least derived
    //
    template<class E, class...Rest>
    std::string catcher_impl()
    {
        try
        {
            std::rethrow_exception(std::current_exception());
        }
        catch(const E& e)
        {
            bool is_exact = typeid(E) == typeid(e);
            return std::string(typeid(E).name()) + (is_exact ? "(exact)" : "(base class)") + " : " + e.what();
        }
        catch(...)
        {
            return catcher_impl<Rest...>();
        }
        return "unknown";
    }

    // specialise for end of list condition
    template<> std::string catcher_impl<void>()
    {
        return "unknown exception";
    }
}

// catcher interface
template<class...Es>
std::string catcher()
{
    return detail::catcher_impl<Es..., void>();
}

// throw some exception type
// and then attempt to identify it using the type list available
//
template<class E>
void test(E&& ex)
{
    try
    {
        throw std::forward<E>(ex);
    }
    catch(...)
    {
        std::cout << "exception is: "
        << catcher<std::invalid_argument, std::system_error, std::runtime_error, std::logic_error>()
        << std::endl;
    }
}

int main()
{
    test(std::runtime_error("hello world"));
    test(std::logic_error("my logic error"));
    test(std::system_error(std::make_error_code(std::errc::filename_too_long)));
    test(std::invalid_argument("i don't like arguments"));

    struct my_runtime_error : std::runtime_error
    {
        using std::runtime_error::runtime_error;
    };
    test(my_runtime_error("an unlisted error"));
}

示例输出:

exception is: St13runtime_error(exact) : hello world
exception is: St11logic_error(exact) : my logic error
exception is: NSt3__112system_errorE(exact) : File name too long
exception is: St16invalid_argument(exact) : i don't like arguments
exception is: St13runtime_error(base class) : an unlisted error