为什么要重新引发异常 在C++中,为什么要重新抛出异常?为什么不让当前catch块处理异常呢。出于什么原因,您会将异常重新发送到另一个try/catch块?

为什么要重新引发异常 在C++中,为什么要重新抛出异常?为什么不让当前catch块处理异常呢。出于什么原因,您会将异常重新发送到另一个try/catch块?,c++,C++,当函数无法满足其约定(它向调用方承诺将执行的操作)时,会引发异常。当一个函数调用另一个抛出异常的函数时,有四种主要的方法来说明它可能如何响应: 捕获异常并处理它。只有当函数能够满足其契约要求时,才应该这样做,尽管抛出了异常。如果它捕获到异常但未能满足其约定,则它对调用代码隐藏了一个问题 允许异常传播。如果此函数无法处理异常(即,由于引发了异常,函数无法满足其约定),并且异常向调用代码公开了适当的信息,则应执行此操作 捕获异常,进行一些清理和/或添加额外信息,然后重新播放它。如果此函数无法处理异常

当函数无法满足其约定(它向调用方承诺将执行的操作)时,会引发异常。当一个函数调用另一个抛出异常的函数时,有四种主要的方法来说明它可能如何响应:

  • 捕获异常并处理它。只有当函数能够满足其契约要求时,才应该这样做,尽管抛出了异常。如果它捕获到异常但未能满足其约定,则它对调用代码隐藏了一个问题

  • 允许异常传播。如果此函数无法处理异常(即,由于引发了异常,函数无法满足其约定),并且异常向调用代码公开了适当的信息,则应执行此操作

  • 捕获异常,进行一些清理和/或添加额外信息,然后重新播放它。如果此函数无法处理异常,但需要在传播之前进行一些清理,则应执行此操作。它还可以提供额外的信息来帮助处理/调试异常(我通常认为程序员是最后一个异常处理程序)

  • 捕获异常并抛出不同的异常(可能是包装原始异常)。如果此函数无法处理异常,但另一个异常可以更好地向调用代码表达问题,则应执行此操作

  • 为什么不让当前catch块处理异常呢。出于什么原因,您会将异常重定向到另一个try/catch块

    异常背后的想法是,您将它们扔到错误站点,并在堆栈中处理它们,在堆栈中您有足够的信息来处理错误

    相反,在某些情况下,如果发生错误,您必须执行某些操作,但仍然不知道如何处理错误(当您重试时就是这种情况)

    例如:

    void connect_and_notify(int connection_data)
    {
        try
        {
            create_network_connection(connection_data); // defined somewhere else
            notify("connection open");                  // same (notify event listeners)
        }
        catch(const std::runtime_error&)
        {
            notify("connection failed");
            throw;
        }
    }
    
    客户端代码:

    void terminal_app_controller()
    {
        try
        {
            connect_and_notify(1);
        }
        catch(const std::runtime_error& err)
        {
            std::cerr << "Connection failed;\n";
            exit(1); // this is usually bad bad code but whatever
        }
    }
    
    void ongoing_server_controller()
    {
        bool connected = false;
        int connection = 1;
        while(!connected)
        {
            try
            {
                connect_and_notify(1);
                connected = true;
            }
            catch(const std::runtime_error&)
            {
                connection++;
            }
        }
    }
    
    void终端\应用\控制器()
    {
    尝试
    {
    连接_和_通知(1);
    }
    捕获(const std::runtime_error&err)
    {
    
    我非常不喜欢像这样的东西

    catch (std::exception&) {
        ... // do some cleanup
        throw;
    }
    
    RAII是该问题的正确解决方案。甚至:

    catch (std::exception&) {
        ... // do some logging here
        throw;
    }
    
    可以用RAII处理,尽管它不那么直观

    但是-我重新下载的是第三方(或供应商提供的)代码抛出“通用”状态异常的任何情况。例如,当将远程通信消息记录到数据库时,我知道我经常收到同一消息的重复副本。每条消息都有一个唯一的ID-因此我的数据库中的主键冲突是“无辜的”应该被静默忽略的错误

    不幸的是,我们使用的DB框架没有针对PK违规引发特定异常-因此我们需要捕获通用dbexception并检查其原因代码以决定要执行的操作。因此:

    catch (db::exception& e) {
        if (e.reason != db::exception::reason::pk_violation)
            throw;
    }
    
    此外,还提到了内部状态

    for (;;) {
        try {
            ...
        }
        catch (some_exception& e) {
            if (retry_count > 3)
                throw;
        }
    }
    

    请记住:如果要重新刷新,请始终通过引用捕获,以避免切片异常对象。(无论如何,您通常应该通过引用捕获,但在重新刷新时更为重要)

    因为包含当前catch块的函数无法执行其任务,并希望抛出异常来表明这一点。!这是家庭作业吗?如果是,您可能希望这样做。如果处理它不是您的工作,为什么您要吞下异常?例如,如果您编写的数据结构需要执行特殊的工作来恢复对象时插入时引发异常,您需要捕获该异常以执行特殊工作,但处理该异常不是您的特权,因为您不知道它在该上下文中的含义。当异常发生时,如果您想执行工作,您可以捕获并重新播放该异常,否则将让异常正常传播。@gnasher729.如果catch块不能处理异常,为什么catch块会捕获异常?“如果catch块不能处理异常,为什么catch块会捕获异常?”也许它在捕获异常后才知道是否可以处理异常。也许它不能处理异常,但需要采取一些本地操作(释放资源、记录故障、回滚事务,或者其他什么)-尽管这通常应该是RAII析构函数的工作。也许它可以向异常添加一些额外的信息,以帮助诊断故障。