【问题标题】:Exception is caught in a constructor try block, and handled, but still gets rethrown a second time异常在构造函数 try 块中被捕获并处理,但仍被再次抛出
【发布时间】:2020-08-07 10:00:32
【问题描述】:

在处理继承时,我试图更好地理解 throw-catch 机制。

我试图解决的问题是如果在构造派生类时首先构造的基类抛出异常会发生什么情况。

#include <stdexcept>
#include <iostream>

class Base
{
    public:
    Base()
    {
        throw  std::runtime_error("test");
    }
};


class Derived : public Base
{
    public:
    Derived() try : Base()
    {

    }
    catch (std::runtime_error& e)
    {
        std::cout <<  "Base throws an exception : " << e.what() << std::endl;
    }    
};


int main ()
{
   Derived temp;
   return (0);
}

运行我的编译代码 (g++ std=11) 后,我收到以下消息:

Base 抛出异常:测试

在抛出 'std::runtime_error' 实例后调用终止

what(): 测试

中止(核心转储

我的 Base 抛出的异常被 Derived 构造函数的 try-catch 捕获,但由于某种原因抛出的异常并没有停止,这是为什么,以及如何解决这个问题?

不管我是否有更好的方法来处理在构造派生时基类可能抛出的异常,我都愿意接受建议。

【问题讨论】:

    标签: c++ inheritance exception try-catch


    【解决方案1】:

    只有在对象的构造函数返回后才能完全构造对象,这是一个基本的 C++ 核心原则。当执行进入类的构造函数时,类本身还没有被构造。只有它的类成员是(以及任何基类)。只有当构造函数返回时,才然后对象被完全构造,你有一个完全熟的对象可以玩。

    因此,构造函数中抛出的异常意味着该对象是没有构造的。句号。故事结局。她就是这么写的。这条规则没有例外(双关语)。

    现在,当您捕获从基类的构造函数抛出的异常时,这意味着什么?好吧,您可以这样做,但它不会改变引发异常并且未构造基类的事实。这意味着不能构造派生类。你不能指望执行到异常处理程序的末尾,然后返回父级,就好像类已经完全构造而没有错误一样。

    这不仅会发生。你不能,不知何故,最终没有构造一个基类,但构造了派生类。 C++ 不能以这种方式工作。

    当您从基类捕获异常时,您只有两种选择:

    1) 你的异常处理程序可以在它做任何它想做的事情之后重新抛出它自己的异常。

    2) 否则,如果异常处理程序返回时没有抛出自己的异常,C++ 将为您重新抛出异常。

    【讨论】:

    • 感谢您的详细回答,在阅读了您的回答后,我又进行了一些谷歌搜索,还有一个很棒的GotW #66 提供了更多信息。
    • 也没有“使用不同参数重试”选项。如果您需要它,请创建一个返回基类实例的辅助函数。该助手可以进行内部故障处理。然后,将该返回的对象传递给基类的移动 ctor。这不应该抛出。
    【解决方案2】:

    是的,这是正确的行为。你有一个 try/catch 块,它从基类和初始化列表中捕获异常。根据标准,此异常会自动从 catch 块中重新抛出。如果您在析构函数中捕获异常,使 try/catch 成为析构函数的主体,情况也是如此。

    【讨论】:

      猜你喜欢
      • 2010-09-13
      • 1970-01-01
      • 1970-01-01
      • 2018-06-05
      • 1970-01-01
      • 2021-01-15
      • 1970-01-01
      • 2013-12-13
      • 2016-04-04
      相关资源
      最近更新 更多