【问题标题】:C++ - finding the type of a caught default exceptionC++ - 查找捕获的默认异常的类型
【发布时间】:2011-02-03 11:04:48
【问题描述】:

说我有:

try
{
 externalLibrary::doSomething();
}
catch (std::exception &e)
{
 //yay I know what to do
}
catch (...)
{
 //darn, I've no idea what happened!
}

在某些情况下,您可能会遇到异常并且您不知道它来自哪里或为什么 - 在一些没有调试信息的外部库中。有没有办法找到抛出的东西,或者以其他方式获取与之相关的任何数据?他们可能在做:

throw myStupidCustomString("here is some really useful information");

但我永远不知道我是否抓住了...

如果重要的话,在 MSVC++ 2008 中工作。

【问题讨论】:

    标签: c++ visual-studio-2008 exception-handling


    【解决方案1】:

    如果您使用 gcc 或 CLANG,您可以使用技巧来了解“未知”异常类型。请记住,这是非标准的!

    #include <cstdlib>
    #include <iostream>
    #include <cxxabi.h>
    
    
    using namespace __cxxabiv1;
    
    std::string util_demangle(std::string to_demangle)
    {
        int status = 0;
        char * buff = __cxxabiv1::__cxa_demangle(to_demangle.c_str(), NULL, NULL, &status);
        std::string demangled = buff;
        std::free(buff);
        return demangled;
    }
    
    struct MyCustomClass
    {};
    
    int main(int argc, char * argv[])
    {
        try
        {
            throw MyCustomClass();
        }
        catch(...)
        {
            std::cout << "\nUnknown exception type: '" << util_demangle(__cxa_current_exception_type()->name()) << "'" << std::endl;
        }
        return(0);
    }
    

    【讨论】:

      【解决方案2】:

      由于 C++ 是静态类型的,因此您必须捕获已知类型。但是,您可以调用一个外部函数(或一组函数)来处理您调用它们时未知的异常类型。如果这些处理程序都具有已知类型,则可以注册它们以进行动态尝试。

      struct myStupidCustomString {
        myStupidCustomString(char const *what) : what (what) {}
        char const *what;
      };
      
      void throws() {
        throw myStupidCustomString("here is some really useful information");
      }
      
      // The external library can provide a function, or you can provide a wrapper, which
      // extracts information from "unknown" exception types.
      std::string extract_from_unknown_external_exception() {
        try { throw; }
        catch (myStupidCustomString &e) {
          return e.what;
        }
        catch (...) {
          throw;  // Rethrow original exception.
        }
      }
      

      Use:

      void example() {
        try { throws(); }
        catch (...) {
          try {
            std::string extracted = extract_from_unknown_external_exception();
            std::cout << "extracted: " << extracted << '\n';
          }
          catch (...) {
            // Chain handlers for other types; e.g. exception types from other libraries.
            // Or do something generic for the unknown exception.
      
            // Or rethrow the original unknown exception:
            throw;
          }
        }
      }
      

      Handler chain:

      typedef std::string Extract();
      std::vector<Extract*> chain (1, &extract_from_unknown_external_exception);
      // Chain would normally be initialized using whatever scheme you prefer for
      // initializing global objects.
      // A list or other container (including a manual linked list that doesn't
      // require dynamic allocation) may be more appropriate, depending on how you
      // want to register and unregister handlers.
      std::string process_chain() {
        for (std::vector<Extract*>::iterator x = chain.begin(); x != chain.end(); ++x) {
          try {
            return (*x)();
          }
          catch (...) {}  // That handler couldn't handle it.  Proceed to next.
        }
        throw;  // None could handle it, rethrow original exception.
      }
      
      void example() {
        try { throws(); }
        catch (...) {
          try {
            std::string extracted = process_chain();
            std::cout << "extracted: " << extracted << '\n';
          }
          catch (...) {
            throw;  // Rethrow unknown exception, or otherwise handle it.
          }
        }
      }
      

      最后,如果您了解实现细节,则可以使用这些信息来提取您的实现公开的任何其他信息。 C++0x 也以可移植的方式公开了一些细节;看看 std::exception_ptr。

      【讨论】:

      • 嗨,我认为这是一个很好的答案。但是,我在标准中找不到任何关于这是否是标准行为的信息。我已经对其进行了测试,它在 VisualStudio、GCC 和 LLVM 中都有效,但我不完全确定为什么。那么输入一个新的try{}catch(){} 块不会以任何方式影响当前的异常吗?谢谢!
      • 我想我也不确定为什么它不起作用..对我来说进入 try 块不会影响任何当前异常似乎是有道理的,但我想我只是想仔细检查。
      【解决方案3】:

      在 C++ 中无法知道异常的类型(当然是在 catch(...) 块中)

      你可以希望你知道 externalLibrary::doSomething(); 到底是做什么的,如果你已经写了它,或者,就像你的情况,你可以希望 externalLibrary::doSomething(); 有非常好的文档并阅读它,如果有的话这样的。所有好的库都有详细的文档。

      【讨论】:

      • 根据我的经验,异常的详细文档不像参数的体面文档那样普遍。但如果是这样的话,我只需要测试标准的可能性......系统异常呢?
      • “系统异常怎么办?”是什么意思?我不知道它们是否可以被 C++ 程序捕获:?此外,我使用的大多数库都有自己的异常层次结构,这些层次结构有据可查。但是,当然,这并不意味着所有图书馆都有这样的东西。另外,如果是 C lib,你知道,不会抛出异常。
      • 我的意思是,没有特殊的方法可以捕获 null-ptr 访问、div/0 等内容吗?我认为有办法在 3rd-party 库有问题的情况下解决此类问题?
      • 我真的不知道。如果有这样的方式那就太好了:)
      【解决方案4】:

      你不能在标准 C++ 中。我认为这样的异常是非常异常的,并通过尝试记录您有严重异常的事实来处理它们,然后尝试退出程序,而您仍然可以。

      如果你幸运的话,你可以保存任何数据。

      【讨论】:

        猜你喜欢
        • 2011-04-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-17
        • 2018-01-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多