错误处理范例:混合异常和错误代码

时间:2011-04-18 19:18:08

标签: c++ design-patterns dll exception-handling error-handling

我目前正在使用各种中间件(包括OGRE(图形),Bullet(物理)和OpenAL(声音))开发C ++游戏引擎,而且我在项目中还很早。正是在这一点上,我正在设置我的错误处理机制。

我计划通过将引擎包含在DLL中并导出一个将返回指向主引擎对象的指针的函数来向用户公开引擎。该对象将包含可以访问引擎的各种组件的方法 - 大多数对象将通过接口访问,以便用户对实际实现隐藏。

我倾向于使用错误代码作为我的错误报告机制而不是异常,因为

  1. 通过DLL链接传递异常会增加错误报告的复杂性,迫使我导出异常类等,
  2. 错误代码通常效率更高,因此它们在实时游戏引擎中很常见。
  3. 然后出现的唯一问题是构造函数 - 它们不能返回错误代码。因此,我计划对所有方法使用错误代码,但在构造函数失败时抛出异常。由于我计划使用工厂方法模式生成对象并将它们传递给用户代码,因此异常将由引擎在内部处理,并且用户只会在构造失败时获得空指针。我意识到你通常不应该混合异常和返回代码,但替代方案听起来不是更好:

    • 您无法在构造函数中执行任何操作并使用某种init()方法,但有RAII。
    • 您可以设置一个标志并使用某种isOk()或isInitialized()方法,但是现在您已经介绍了某些僵尸状态的可能性,其中对象存在但无法初始化,您可能忘记检查确保它还活着。

    我知道这两个系统固有的成本和收益,并意识到混合这两个系统通常是一个坏主意。但是,由于构造函数不能具有某种返回值,因此当构造函数失败并在其他地方使用错误代码时抛出异常会不合理吗?有人有更好的建议吗?

3 个答案:

答案 0 :(得分:1)

我个人更喜欢例外(并且有很多很好的理由)。但当然,将DLL代码中的异常抛给用户代码(反之亦然)是一个坏主意。所以在你的情况下,我会在模块中使用异常(包括DLL和可执行文件),并使用基于error_return的API进行DLL导出。当使用DLL的基于error_return的API时,我会为那些error_returning函数使用基于异常的包装器。

IMO以任何方式返回错误指示符(通过返回值或通过引用或通过每个线程的错误代码)可能会使代码无休止地错误检查分支。我的方式(以及我对C ++方式的理解)仅在成功的情况下才会返回。

答案 1 :(得分:0)

在你的情况下,我会说螺旋RAII并使用Init方法。混合两种范例不仅会降低一致性,还会迫使引擎的消费者在某些人不愿意的情况下实现异常处理机制。

答案 2 :(得分:0)

我现在更喜欢只处理异常,但如果您仍然需要或想要使用构造函数的错误代码,我喜欢的方法是强制用户在构造函数中传递参数:

class Foo {
    public:
        Foo(int &errorCode) {
            //our init code
            rc = SOMETHING_BAD;
        }
};

//on a method or function:
int errorCode;
Foo foo(errorCode);
if(errorCode != RESULT_OK)
{
      //handle it
}

我认为这比使用IsOk()方法或单独的Init方法更好,因为它至少会强制用户将变量作为参数传递,并且很难忘记检查错误,缺点是有时候它为此仅仅声明变量很无聊。

我的2美分。