哪一个是更好的错误处理方法?

时间:2014-07-30 05:00:25

标签: c++ c++11 error-handling lambda goto

假设您在函数中有多个点可能导致相同的失败。哪种方法会更好?还有更好的选择吗?

{
    ...
    if (some_failure_condition0) goto fail;
    ...
    if (some_failure_condition1) goto fail;
    ...
    if (some_failure_condition2) goto fail;
    ...
    if (...) {
        ...
    }
    else if (...) {
        ...
    }
    else goto fail;
    ...
    return;

fail:
    /* handle error here */
    ...
}

{
    auto fail = [] {
        /* handle error here */
        ... 
    };
    ...
    if (some_failure_condition0) fail();
    ...
    if (some_failure_condition1) fail();
    ...
    if (some_failure_condition2) fail();
    ...
    if (...) {
        ...
    }
    else if (...) {
        ...
    }
    else fail();
    ...
}

5 个答案:

答案 0 :(得分:1)

由于这是C ++而不是C,更好的选择是使用有助于保证正确调用析构函数的异常:

try
{
    ...
    if (some_failure_condition0) throw fail;
    ...
    if (some_failure_condition1) throw fail;
    ...
    if (some_failure_condition2) throw fail;
    ...
    if (...) {
        ...
    }
    else if (...) {
        ...
    }
    else throw fail;
    ...
    return;
}
catch(const fail& f)
    /* handle error here */
    ...
}

答案 1 :(得分:1)

一般来说,这完全取决于函数的语义。我通常会避免goto(我多年没有使用它),并且还避免使用返回码进行C风格的错误处理。对于错误处理,我遵守以下准则:

  1. 使用RAII资源获取自动异常安全处理,例如:没有明确的新来电。
  2. 当函数无法建立其后置条件(以及类不变,如果它是成员函数)时,抛出异常。我会...抛出要从其接收数据的网络连接未打开,但如果由于没有可用数据而通过网络接收数据失败则不会。
  3. 如果“错误”是该功能的预期结果,例如通过网络接收数据但没有人发送数据,我会使用一个可以处理数据的返回类型。在示例中,它可能是一个空向量,但通常像boost :: optional这样的东西是有道理的。
  4. 完成功能时需要执行的代码应该在范围保护中。这通常是临时RAII对象,因此我经常创建一个新的RAII来重复使用它。
  5. 这使得像你的例子的代码在我生命中的大部分时间都已经过时了。

答案 2 :(得分:0)

这个怎么样?

#define MY_FAIL_CHECK(_condition) if(_condition) { throw some_exception; }

void foo()
{
  MY_FAIL_CHECK(some_failure_condition0);
  MY_FAIL_CHECK(some_failure_condition1);
  MY_FAIL_CHECK(some_failure_condition2);
}

答案 3 :(得分:0)

如果您使用的是C ++,则没有合理的理由使用goto代替例外。

答案 4 :(得分:0)

我会创建子函数,如:

bool foo() // or enum or boost::optional
{
    ...
    if (some_failure_condition0) return false;
    ...
    if (some_failure_condition1) return false;
    ...
    if (some_failure_condition2) return false;
    ...
    if (...) {
        ...
    }
    else if (...) {
        ...
    }
    else return false;
    ...
    return true;
}

void bar()
{
    auto result = foo();
    if (!result)
    {
        /* handle error here */
        ...
    }
}

不要忘记使用RAII来避免一些可能是自动的处理。

相关问题