编码样式 - 输入验证

时间:2009-01-23 19:03:23

标签: c++ coding-style

这是验证传递给函数的输入的最佳方法,即在继续进行某些操作之前验证所有输入

class A;
void fun(A* p)
{
  if(! p)
  {
    return;
  }

 B* pB = p->getB();
  if(! pB)
  {
    return;
  }

.......

}

或者你这样写:

void fun(A* p)
{
  if(p)
  {
    B* pB = p->getB();
    if(pB)
    {
      .....
    }
  }
}

我问这个是因为,如果我使用第一个样式,那么我的代码中会有多个return语句,很多人说这些语句很糟糕(不知道为什么),如果我使用第二个样式那么就会有我的代码中嵌套的级别太多了。

7 个答案:

答案 0 :(得分:7)

第一种方式比第二种方式更容易阅读,更简单(深度)。在第二个中,随着参数数量的增加,复杂性和深度增加。但在第一个例子中,它只是线性的。

答案 1 :(得分:4)

多重回报:人和编码标准都是双向的。在C ++中,imo没有理由不喜欢多个返回(和异常),如果你正在使用RAII等。许多C编码标准强制执行单入口单一退出以确保所有清理代码都被执行,因为没有RAII和基于范围的销毁/资源清理。

Should a function have only one return statement?

答案 2 :(得分:1)

我更喜欢提前进行输入验证,但通常会同时执行所有测试

if(!p || !p->getB()){
    return;
}

如果函数需要输入,并且语言支持它,则抛出Argument Exceptions(请参阅.NET ArgumentNullException,ArgumentException),以便在无效状态的情况下代码不会执行clean返回。这使得调用者知道参数不足以完成操作。

答案 3 :(得分:1)

我更喜欢第一个,直到我有一组宏来处理常见情况(并且通常在调试时同时断言)。这种方法的缺点是你的函数返回类型必须相当统一,以使你的宏用法统一;好处是使用/效果非常明显。因此,例如,我的代码可能是:

class A;
void fun(A* p)
{
  ASSERT_NONZERO_RETURN_ON_FAIL( p );

  B* pB = p->getB();
  ASSERT_NONZERO_RETURN_ON_FAIL( pB );

  .......
}

这会导致更易读的代码,它也会提醒您出错。此外,作为一个额外的好处,如果您发现您将边际速度增加值超过运行时检查的值,则可以轻松禁用检查发布版本。

补充说明:根据我的经验,有些人说函数的多个返回点是坏的原因是因为他们在函数退出之前明确地进行资源解除分配,因此你不想复制解除分配代码。但是,如果您正确且统一地使用RIIA,这应该不是问题。因为这也是我总是这样做的,所以多个返回点比我的嵌套更可取。

答案 4 :(得分:1)

我倾向于使用这些类型的检查并在方法的开头返回。 所以我有点模仿 Eiffel design by contractpreconditionsassertions, 如描述的那样 Bertrand Meyer'sObject-Oriented Software Construction, second edition, Prentice Hall

对于你的例子,我会返回而不是返回void 识别违规行为的枚举:

enum Violation { inviolate = 0, p_unspecified_unavailable, p_B_unspecified_unavailable,..... };

Violation fun(A* p)
{
//__Preconditions:___________________________________
  if (! p)         return p_unspecified_unavailable:
  if (! p->getB()) return pB_unspecified_unavailable;
//__Body:____________________________________________
   ....
//__Postconditions: _________________________________
   ..(if any)..
   return inviolate;
}

我的观点是,我考虑前提条件(以及任何后置条件)验证 围绕方法/功能体的实现并倾向于 区分和分离控制条件逻辑的流程与身体的表达。

答案 5 :(得分:0)

理想情况下,你会通过引用传递,然后你不必担心这个问题。但这并不总是一种选择。否则这是一个偏好的问题。

我个人喜欢第一个,因为我没有太多的回报问题。我认为函数应该基本上适合一个或两个屏幕,所以只要你有语法高亮,就不应该很难看到所有函数的退出点。

答案 6 :(得分:0)

我使用您发布的第一种方法,在大多数情况下,这允许我提供:有意义的返回值或向用户发送消息:


btnNext_OnClick(...)
{
if(!ValidateData())
 return;

// do things here
}


boolean ValidateData()
{
if(!condition)
{
 MessageBox.Show("Message", "Title", MessageBoxButtons.OK, MessageBoxIcons.Information);
 return false;
}

return true;
}

这样,当我添加需要表单级别验证的字段时,我可以在验证方法中添加另一个if语句检查。