【问题标题】:How to change my error handling method如何更改我的错误处理方法
【发布时间】:2010-11-22 09:32:05
【问题描述】:

我似乎无法理解为什么人们说 C++ 异常更好。例如,我有一个应用程序,它从共享对象中加载要在应用程序中使用的函数对象。发生的事情是这样的:

bool LoadFunctions()
{
   //Get Function factory.
   FunctionFactory& oFactory = GetFunctionFactory();
   //Create functions from the factory and use.
}

FunctionFactory& GetFunctionFactory()
{
   //Get shared object handle.
   void* pHandle = dlopen("someso.so");

   //Get function ptr for Factory getter.
   typedef FunctionFactory* (*tpfFacGet)();
   tpfFacGet pF = static_cast<tpfFacGet>(dlsym(pHandle, "GetFactory"));

   //Call function and return object.
   return *((*pF)());
}

现在,很容易看出很多东西都可能出错。如果我像往常一样这样做,我会返回指针而不是引用,我会检查它们是否为NULL 并打印一条错误消息,如果不是则退出。这样,我知道哪里出了问题,我什至可以尝试从中恢复(即,如果我成功加载工厂并且未能加载一个函数,我可能仍会继续)。我不明白的是如何在这种情况下使用异常以及如何恢复程序而不是打印错误消息和qutting。有人可以告诉我如何以 C++ 方式执行此操作吗?

【问题讨论】:

    标签: c++ exception-handling error-handling


    【解决方案1】:

    我们甚至不需要返回码。如果出现问题,它应该在异常中。

    int main()
    {
        try
        {
            LoadFunctions();
            // if we're here, everything succeeded!
        }
        catch(std::exception _e)
        {
            // output exception message, quit gracefully
        } 
    
        // IRRESPECTIVE OF SUCCESS/FAILURE WE END UP HERE
    
        return 0;
    } // eo main
    

    编辑:

    好的,假设您有另一种加载函数的方法,如果LoadFunctions() 失败。您可能很想在 catch 处理程序中调用它,但这样您很快就会得到大量嵌套的异常处理程序,这会使事情变得复杂。

    所以现在我们开始讨论设计的问题。 LoadFunctions 如果加载了函数,则应该成功,如果没有,则抛出异常。在这个加载函数的替代方法的假设示例中,该调用应该在LoadFunctions 方法中。这种替代方法不需要对调用者可见。

    在顶层,我们要么得到函数,要么没有。编写良好的异常处理,在我看来是关于摆脱灰色区域。该函数执行了它被告知执行的操作,或者没有执行。

    【讨论】:

    • "// 输出异常信息,优雅地退出" - 这正是我不明白的事情。如果我不想辞职怎么办?那我该怎么办?
    • 如果你不想退出,就在catch块里写下你想做的吧。
    • 就是这么简单,然后你就知道你的GetFunctionFactory函数总是返回一致的结果,省去了每次使用都检查的必要。
    • @Simone :我可以看到什么范围?我将从哪里继续。 (何时/之后)我击中了 catch 块?如果问题出在深度嵌套的函数中怎么办?
    • 您可以访问 catch 块的局部变量和 try 块之外的块。在 catch-block 之后,您将在此示例中以 return 0; 结束
    【解决方案2】:

    正如您所说,有很多地方可能会出错。顺便说一句,你不会在那里看到一个糟糕的演员阵容。如果符号存在但不是您要转换的类型,那么您以后只会感到震惊。

    如果您要避免异常,您将需要在某个地方报告错误。由于您的 LoadFunctions 和 GetFunctionFactory() 不知道您希望如何处理错误(记录它?将其打印到 stderr?放置一个消息框?)它唯一能做的就是生成错误。

    在 C 中的一种常见方法是传入一个参数,如果发生错误,它可以将错误放入其中,并在继续之前让每个函数“检查”成功。这会使流程变得相当棘手。

    “抛出”异常的 C++ 概念意味着您不需要通过每个函数继续传递指针(或引用)。在发生错误的地方生成它并“抛出”它——有点像“喊”它。这会导致所有代码(除析构函数中的清理之外)暂停,直到找到以所需方式处理错误的捕获器。

    请注意,异常通常只能用于处理错误,而不是像遇到“文件结尾”这样的正常情况,因为这是您知道读取已完成的方式。

    【讨论】:

      【解决方案3】:

      使用异常而不是返回值(或任何其他方法)不应该改变代码的行为,只会改变它的编写和组织方式。这基本上意味着首先你决定你对某个错误的恢复是什么,无论是更优雅还是更少,然后你编写代码来执行它。 大多数有经验的程序员(实际上都是)同意异常是比返回值更好的方法。您无法在几个函数的简短示例中看到很大的差异,但在包含数千个函数和类型的实际系统中,您会清楚地看到它。我不会详细说明它如何更好。 我建议无论如何你应该习惯于默认使用异常。但是请注意,使用异常有一些微妙的问题(例如 RAII http://en.wikipedia.org/wiki/RAII),最终会使您的代码更好,但您应该在一本书中阅读它们(我将无法在这里描述并觉得我是公正的到主题)。 我认为“Effective c++ / Scott Meyer”一书涉及到这一点,当然是“Exceptional C++ / Herb Sutter”。如果您还没有读过这些书,那么这些书对于任何 C++ 开发人员来说都是一个很好的起点。

      【讨论】:

        猜你喜欢
        • 2018-12-12
        • 1970-01-01
        • 2018-01-09
        • 1970-01-01
        • 2011-10-27
        • 2011-01-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多