【问题标题】:How can I catch all types of exceptions in one catch block?如何在一个 catch 块中捕获所有类型的异常?
【发布时间】:2010-09-08 12:34:49
【问题描述】:

在 C++ 中,我试图一次捕获所有类型的异常(例如 C# 中的 catch(Exception))。它是如何完成的?更重要的是,如何捕获被零除的异常?

【问题讨论】:

    标签: c++ exception-handling try-catch


    【解决方案1】:

    您可以使用catch(...) 来捕获所有内容,但随后您无法获得一个对象来检查、重新抛出、记录或执行任何操作。所以......你可以“加倍” try 块并重新抛出一个处理单一类型的外部捕获。如果您为自定义异常类型定义构造函数,该类型可以从您想要组合在一起的所有类型构建自身,则此方法非常有效。然后,您可以从catch(...) 中抛出一个默认构造的,其中可能包含一条消息或代码,例如“未知”,或者您想要跟踪此类内容。

    例子:

    try
    { 
        try
        {       
            // do something that can produce various exception types
        }
        catch( const CustomExceptionA &e ){ throw e; } \
        catch( const CustomExceptionB &e ){ throw CustomExceptionA( e ); } \
        catch( const std::exception &e )  { throw CustomExceptionA( e ); } \
        catch( ... )                      { throw CustomExceptionA(); } \
    } 
    catch( const CustomExceptionA &e ) 
    {
        // Handle any exception as CustomExceptionA
    }
    

    【讨论】:

      【解决方案2】:

      想要使用 catch (...)(即带有省略号的 catch),除非您确实、肯定、最可证明的需要它。

      原因是一些编译器(最常见的是 Visual C++ 6)也会将诸如分段错误和其他非常糟糕的情况之类的错误转换为您可以使用 catch (...) 轻松处理的异常。这很糟糕,因为您再也看不到崩溃了。

      从技术上讲,是的,您也可以捕获除以零(为此您必须使用“StackOverflow”),但您确实应该首先避免进行此类除法。

      相反,请执行以下操作:

      • 如果您确实知道会发生什么样的异常,请仅捕获这些类型,然后
      • 如果您需要自己抛出异常,并且需要捕获您将抛出的所有异常,请使这些异常派生自 std::exception(如 Adam Pierce 建议的那样)并捕获它。

      【讨论】:

        【解决方案3】:

        当然,您可以使用catch (...) { /* code here */ },但这真的取决于您想要做什么。在 C++ 中,你有确定性析构函数(没有那些终结的垃圾),所以如果你想清理,正确的做法是使用 RAII。

        例如。而不是:

        void myfunc()
        {
            void* h = get_handle_that_must_be_released();
            try { random_func(h); }
            catch (...) { release_object(h); throw; }
            release_object(h);
        
        }
        

        执行以下操作:

        #include<boost/shared_ptr.hpp>
        
        void my_func()
        {
            boost::shared_ptr<void> h(get_handle_that_must_be_released(), release_object);
            random_func(h.get());
        }
        

        如果您不使用 boost,请使用析构函数创建您自己的类。

        【讨论】:

          【解决方案4】:
          catch (...)
          {
             // Handle exceptions not covered.
          }
          

          重要注意事项:

          • 一种更好的方法是捕获您实际上可以从中恢复的特定类型的异常,而不是所有可能的异常。
          • catch(...) 还将捕获某些严重的系统级异常(因编译器而异),您将无法可靠地从中恢复。以这种方式捕捉它们然后吞下它们并继续可能会导致您的程序出现更多严重问题。
          • 根据您的上下文,可以接受使用 catch(...),前提是重新抛出异常。在这种情况下,您记录所有有用的本地状态信息,然后重新抛出异常以允许它向上传播。但是,如果您选择这条路线,您应该阅读RAII pattern

          【讨论】:

            【解决方案5】:

            如果您在 Windows 上并且需要处理除以零和访问冲突等错误,您可以使用结构化异常转换器。然后在你的翻译器中你可以抛出一个 c++ 异常:

            void myTranslator(unsigned code, EXCEPTION_POINTERS*)
            {
                throw std::exception(<appropriate string here>);
            }
            
            _set_se_translator(myTranslator);
            

            注意,代码会告诉你错误是什么。您还需要使用 /EHa 选项进行编译(C/C++ -> Code Generatrion -> Enable C/C++ Exceptions = Yes with SEH Exceptions)。

            如果这没有意义,请查看 [_set_se_translator](http://msdn.microsoft.com/en-us/library/5z4bw5h5(VS.80).aspx)

            的文档

            【讨论】:

              【解决方案6】:

              如果您确实需要捕获所有异常(包括操作系统异常),则需要查看您的编译器和操作系统。例如,在 Windows 上,您可能有“__try”关键字或编译器开关以使“try/catch”捕获 SEH 异常,或两者兼而有之。

              【讨论】:

                【解决方案7】:

                在 C++ 中,标准没有定义被零除异常,实现往往不会抛出它们。

                【讨论】:

                  【解决方案8】:

                  如果我没记错的话(我已经有一段时间没有看过 C++了),我认为下面的方法应该可以解决问题

                  try
                  {
                   // some code
                  }
                  catch(...)
                  {
                   // catch anything
                  }
                  

                  而且快速谷歌 (http://www.oreillynet.com/pub/a/network/2003/05/05/cpluspocketref.html) 似乎证明我是正确的。

                  【讨论】:

                  • 在 Windows 和其他系统中可能不安全。它会阻止访问违规和其他非常糟糕的事件。
                  【解决方案9】:

                  让你所有的自定义异常类都继承自 std::exception,然后你就可以简单地捕获 std::exception。下面是一些示例代码:

                  class WidgetError
                      : public std::exception
                  {
                  public:
                      WidgetError()
                      { }
                  
                      virtual ~WidgetError() throw()
                      { }
                  
                      virtual const char *what() const throw()
                      {
                          return "You got you a widget error!";
                      }
                  };
                  

                  【讨论】:

                  • 这是一种很好的做法,可以减少捕获块的数量。正如其他人所指出的那样, catch(...) 通常是不安全的。在 unicode 下编译时,std::exception 有点乱。 (因为 what() 返回一个 char 字符串,而不是 wchar_t 字符串)
                  猜你喜欢
                  • 2012-01-16
                  • 1970-01-01
                  • 2011-07-30
                  • 2013-11-15
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-06-04
                  • 2018-05-23
                  相关资源
                  最近更新 更多