【问题标题】:Is there any way to get some information at least for catch(...)?有什么方法可以至少为 catch(...) 获取一些信息?
【发布时间】:2009-06-28 17:13:56
【问题描述】:

有什么方法可以在这里获取至少一些信息吗?

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

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

【问题讨论】:

  • 请注意,GCC 有一个头文件 cxxabi.h,其中包含一个 __cxa_current_exception_type(); extern "C" 函数,它返回一个 std::type_info 对象和一个 __cxa_demangle 去角化。使用codesourcery.com/public/cxx-abi/abi.html 指定的这两个函数,您可以在 GCC 上打印异常的类型。

标签: c++ exception exception-handling


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

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

    一旦您弄清楚异常是什么,您应该尝试用源自std::exception 的东西替换或扩充它。必须catch (...) 一点都不好。

    如果你使用 GCC 或 Clang,你也可以尝试__cxa_current_exception_type()-&gt;name() 来获取当前异常类型的名称。

    【讨论】:

      【解决方案3】:

      是的,但它有多大用处还有待商榷:

      #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;
              }
          }
      }
      

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

      【讨论】:

      • 但这并没有抓住 throw 7
      • 可能 - 但最初的问题是关于从 catch(...) 中提取“一些”信息,这是我知道的唯一方法。
      【解决方案4】:

      我相信您应该抓住 (...),如果您当时有合理的行动方案并希望应用程序继续运行。

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

      【讨论】:

        【解决方案5】:

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

        如果你愿意,这个想法可以扩展到异常类型的动态注册表中,你需要注意的是确保列表按照从最多派生到最少派生的顺序(需要一个 lot 注册过程中的重新投掷和捕捉!)

        #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
        

        【讨论】:

          猜你喜欢
          • 2013-03-26
          • 1970-01-01
          • 2019-10-06
          • 2020-08-17
          • 2019-01-11
          • 1970-01-01
          • 2013-10-25
          • 1970-01-01
          • 2012-02-19
          相关资源
          最近更新 更多