1

我正在研究函数调用的错误测试和报告技术,尤其是在调用多个函数时。作为我的意思的一个例子,为简单起见,每个函数都返回一个布尔值:

success = false;

if (fnOne ())
{
    if (fnTwo ())
    {
        if (fnThree ( ))
        {
            success = true;
        }
        else
        {
            cout << "fnThree failed" <<endl;
        }
    }
    else
    {
        cout << "fnTwo failed" <<endl;
    }
}
else
{
    cout << "fnOne failed" <<endl;
}

我发现上面的例子(我到处都能看到)代码很快变得不可读,尤其是当它调用代码变得多屏时。

目前我在 C++ 中处理这个问题的方式(包括'c'标签,以防有人拥有流畅的 C 技术)我在我的对象中存储了一个 bool 和一个字符串。bool 代表成功/失败,字符串代表失败状态的原因。我调用一个函数,如果函数失败,该函数在内部将对象设置为失败状态并提供基于字符串的原因。我仍然对这种方法不是 100% 满意......但它是迄今为止我所拥有的最好的。它的外观示例:

void myobj::fnOne (void)
{
    if (m_fluxCapacitorProngCount > 3)
    {
        setState (false, "myobj::fnOne - Flux capacitor has been breeding again");
    }
}

void myobj::fnTwo (void)
{
    if (m_answerToLifeUniverseAndEverything != 42)
    {
        setState (false, "myobj::fnTwo - Probability drive enabled?");    
    }
}

void myobj::setup (void)
{
    // Ensure time travel is possible
    if (valid())
    {
        fnOne ();
    }

    // Ensure the universe has not changed
    if (valid())
    {
        fnTwo ();
    }

    // Error? show the reason
    if (valid() == false)
    {
        cout << getStateReason () << end;
    }
}

其中valid()返回true/false,getStateReason()返回错误发生时函数中提供的字符串。

我喜欢它不需要嵌套条件就可以增长,对我来说我觉得这更具可读性,但我确信存在问题......

处理检测和报告多个函数调用返回条件的最佳 [干净] 方法是什么?

4

3 回答 3

2

此代码应该比您的第一个变体更清晰:

if (!fnOne ())
{
    cout << "fnOne failed" <<endl;
    return;
}
if (!fnTwo ())
{
    cout << "fnTwo failed" <<endl;
    return;
}
if (!fnThree ())
{
    cout << "fnThree failed" <<endl;
    return;
}
success = true;

通常,对于 C++,您可以使用异常来处理错误。

于 2014-03-21T15:32:28.207 回答
0

处理代码中的错误(bug)和用户输入引起的错误本身就是一个巨大的话题。您采用的技术取决于代码的复杂性和代码的预期寿命。您为家庭作业项目采用的错误处理策略不如您为学期项目采用的错误处理策略复杂,后者比您为内部项目采用的错误处理策略简单,后者将是比将广泛分发给客户的项目更简单。

策略 1:写入错误消息并中止

您可以在家庭作业项目中使用的最简单的错误处理策略是将消息写入stdout然后调用abort().

void fun1(int in)
{
  if (in < 0 )
  {
    printf("Can't work with a negative number.\n");
    abort();
  }

  // Rest of the function.
}

策略二:设置全局错误码并返回

下一级错误处理涉及检测错误输入并在不调用abort(). 您可以设置一个全局可访问的错误代码来指示错误的类型。我建议将这种方法用于家庭作业项目、学期项目和探索性项目。

void fun2(int in)
{
  if (in < 0 )
  {
    // Indicate that "fun2" came accross a NEGATIVE_INTEGER_ERROR.
    setErrorCode(NEGATIVE_INTEGER_ERROR, "fun2");
    return;
  }

  // Rest of the function.
}

void funUser(int in)
{
  // Call fun2
  fun2(in);

  // If fun2 had any errors, deal with it.
  if (checkErrorCode())
  {
     return;
  }

  // Rest of the function.
}

下一级错误处理涉及检测错误输入并使用其他选项进行处理。您可以从函数返回错误代码。如果您使用的是 C++,则可能会引发异常。这两种选择都是处理大型项目的有效方式——无论是在内部还是为了更广泛的使用而分发。它们适用于用户群超出开发团队的任何项目。

策略 3:从函数返回错误代码

int fun3(int in)
{
  if (in < 0 )
  {
    // Indicate that "fun3" came accross a NEGATIVE_INTEGER_ERROR.
    return NEGATIVE_INTEGER_ERROR;
  }

  // Rest of the function.
}

void funUser(int in)
{
  // Call fun3
  int ecode = fun3(in);

  // If fun3 had any errors, deal with it.
  if (ecode)
  {
     return;
  }

  // Rest of the function.
}

策略 4:从函数中抛出错误代码 (C++)

void fun4(int in)
{
  if (in < 0 )
  {
    // Indicate that "fun4" came accross a NEGATIVE_INTEGER_ERROR.
    throw NEGATIVE_INTEGER_ERROR;
  }

  // Rest of the function.
}

void funUser(int in)
{
  // Call fun4. Be prepared to deal with the exception or let it be
  // dealt with another function higher up in the call stack.
  // It makes sense to catch the exception only if this function do
  // something useful with it.
  fun4(in);

  // Rest of the function.
}

希望这为您提供了足够的背景知识,以便为您的项目采用适当的错误处理策略。

于 2014-03-21T17:03:06.023 回答
0

如果您真的希望一个函数返回一个表示其他几个函数的成功/失败的值(仅此而已 - 不是每个函数的通用返回值,这需要某种方式返回值的数组/元组/向量) ,这是一种方法:

int bigFunction()
{ int return_value = 0;

  if (function1() != 0)
    return_value |= (1 << 0);

  if (function2() != 0)
    return_value |= (1 << 1);

  if (function3() != 0)
    return_value |= (1 << 2);

  // ....

  return return_value;
}

这个想法是在返回值中分配一个位来指示每个子功能的成功/失败。如果您的子函数具有您实际想要捕获的一小组可能的返回值,则每个函数可以使用多个位 - 即两位将允许您为该字段提供四个不同的值。

另一方面,这样的事情意味着您可能要么 a) 编写一些非常低级的代码,如设备驱动程序或内核或其他东西,要么 b) 可能有更好的方法来解决手头的问题。

于 2014-03-21T16:21:35.393 回答