【问题标题】:Catching c++ base exceptions捕获 c++ 基本异常
【发布时间】:2009-02-12 12:43:54
【问题描述】:

在我的项目中,我们有一个基本异常。用于处理显示错误对话框、日志等。 我正在寻找一种方法来处理该异常的所有派生类,我认为这会起作用:

try
{
  main_loop();
}
catch (const MyExceptionBase* e)
{
  handle_error(e);
}

因为每个抛出的子实例都可以用指向其父实例的指针来表示。但是不,当现在抛出异常时,它是一个未处理的异常。

这是为什么? c++ 只抛出异常作为引用吗?从而使我的 catch 块无用?但是为什么这首先会编译呢?

我能想到的唯一其他方法是:

try
{
  main_loop();
}
catch (const ExceptionA& e)
{
  handle_error(e);
}
catch (const ExceptionB& e)
{
  handle_error(e);
}
catch (const ExceptionC& e)
{
  handle_error(e);
}

这看起来有点难看。这样做的正确方法是什么?没有基础异常类?还是可以按照我想要的方式解决?

Ps:handle_error() 所做的只是简单地利用基类函数display_message_box() 并干净地关闭程序。

【问题讨论】:

    标签: c++ exception try-catch


    【解决方案1】:

    我很惊讶你原来的例子不起作用。以下确实有效(至少对于 g++):

    class Base { public: virtual ~Base () {} };
    class Derived : public Base {};
    
    int main ()
    {
      try
      {
        throw new Derived ();
      }
      catch (Base const * b)
      {
        delete b;
      }
    }
    

    我也很确定这是为了按照 15.3/3 下的项目符号工作:

    处理程序的类型为 cv1 T* cv2,E 是一个指针类型,可以通过两者之一或两者转换为处理程序的类型

    您是否通过公共继承从基本异常类型继承?基类必须是可访问的基类,这将阻止您的异常被捕获。

    根据此处的所有其他答案,通过引用进行投掷/捕获的优势在于您无需担心内存的所有权等问题。但如果上面的示例不起作用 - 那么我不知道为什么参考示例会起作用。

    【讨论】:

    • 是的,确实有效。我的代码没有的原因是我用“throw ExceptionA;”抛出异常,没有“new”,所以从来没有指针。但正如 jpalecek 所说,对父母的引用显然也可以指向孩子,我不知道,但它现在似乎有效。
    • 注意一点,确保异常层次结构的析构函数和复制构造函数绝对不会抛出异常。您的对象可能会被复制到“临时异常对象”,并且该复制不应失败。析构函数也是如此。
    • @mizipzor:我怀疑这是问题所在。如果你抛出一个对象,你需要用一个对象(但不要这样做)或对象引用来捕捉它,你不能用指向对象的指针来捕捉它。使用“catch const MyExceptionBase* e)”你只能捕捉指针(但也不要这样做)。
    • +1 理查德·科登。我知道需要不抛出的析构函数,但不知道需要不抛出的复制 ctor。
    • "您是否通过公共继承从基本异常类型继承?"是一个有用的提示。
    【解决方案2】:

    只需混合使用这两种方法:使用基类和使用引用。

    try
    {
      main_loop();
    }
    catch (const MyExceptionBase& e)
    {
      handle_error(e);
    }
    

    BTW C++ 可以捕获指针,如果你抛出它们。但这并不可取。

    【讨论】:

    • 我不知道引用也可以引用派生类实例,我试试看,谢谢! :)
    【解决方案3】:

    最好的办法是捕捉基本参考。但请通过引用而不是指针来完成。示例

    try
    {
      main_loop();
    }
    catch (const MyExceptionBase& e)
    {
      handle_error(e);
    }
    

    通过指针捕获异常的问题是它必须由指针抛出。这意味着它将使用 new 创建。

    throw new ExceptionA();
    

    这会留下一个相当大的问题,因为它必须在某个时候被删除,否则你就会出现内存泄漏。谁应该负责删除此异常?通常很难做到这一点,这就是为什么大多数人通过参考来捕捉。

    通常在 C++ 中你应该...

    按引用捕获,按值抛出

    【讨论】:

    • +1 用于按引用捕获按值抛出。谁说的 - 萨特?
    • @Greg,我知道 Sutter 在他的书中说过,但我不确定他是否是原始来源。
    【解决方案4】:

    只有在抛出指针时才能使用catch( const sometype* ptr ),这在 99% 的情况下是不可取的。

    catch( const sometype& ptr ) 起作用的原因是因为 r 值可以隐式转换为常量引用。

    【讨论】:

      【解决方案5】:

      这应该可行:

      try {
        main_loop();
      } catch (const MyExceptionBase &e) {
        handle_error(e);
      }
      

      我假设 ExceptionA/B/C 都继承自 MyExceptionBase...我认为应该可以正常工作。

      PS:您可能需要考虑从 std::exception 继承 MyExceptionBase。

      【讨论】:

      • 从 std::exception 继承有什么额外的好处吗?
      • 不是很大,也许未捕获的异常可以有更有意义的消息(因为许多终止处理程序输出 what() 成员)。
      【解决方案6】:

      正如其他人所提到的,您应该捕获对基类异常的引用。

      至于为什么它首先编译,与Java不同的是,对于可以抛出或捕获的类型没有任何限制。因此,您可以为任何类型放入一个 catch 块,即使它从未被抛出,您的编译器也会很高兴地编译它。既然你可以通过指针抛出,你也可以通过指针捕捉。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-04-03
        • 1970-01-01
        • 1970-01-01
        • 2012-08-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-30
        相关资源
        最近更新 更多