是“if(...)return ...;”没有“别的”被认为是好风格?

时间:2010-11-21 13:31:10

标签: c++ if-statement

此代码:

if( someCondition )
    return doSomething();

return doSomethingElse();

与此代码对比:

if( someCondition )
    return doSomething();
else
    return doSomethingElse();

从本质上讲,它们是相同的,但什么是最好的风格/表现/ ...(当然,如果答案中有任何非自以为是的部分)?还要考虑具有多个“if else's”的情况:

if( someCondition )
    return doSomething();
else if( someOtherCondition )
    return doSomethingDifferently();
//...
else
    return doSomethingElse();

谢谢!

5 个答案:

答案 0 :(得分:43)

如果函数中有多个return语句,则称为“提前返回”。如果您为“提前退货”执行了Google search,则会在链接后发现链接显示该链接很糟糕。

我说废话。

有两个主要原因和一个次要原因是人们声称早期回归是坏事。我将通过它们并按顺序给出我的反驳。请记住这是我的全部意见,最终你必须自己决定。

1)原因:提前退货使其难以清理。

反驳:这就是RAII的用途。精心设计的程序不会以这样的方式分配资源:如果执行早期离开范围,那么这些资源就会泄漏。而不是这样做:

...

int foo()
{
  MyComplexDevice* my_device = new MyComplexDevice;
  // ...
  if( something_bad_hapened )
    return 0;
  // ...
  delete my_device;
  return 42;
}

你这样做:

int foo()
{
  std::auto_ptr<MyComplexDevice> my_device(new MyComplexDevice);
  if( something_bad_hapened )
    return 0;
  // ...
  return 42;
} 

提前退货不会导致资源泄漏。在大多数情况下,您甚至不需要使用auto_ptr,因为您将创建数组或字符串,例如,您将使用vectorstring或类似的东西。

由于存在异常的可能性,您应该设计这样的代码以保持稳健性。异常是一种早期返回的形式,如明确的return语句,您需要准备好处理它们。您可能无法在foo()中处理异常,但foo()无论如何都不会泄露。

2)原因:早期返回使代码更复杂。     反驳:早期的回报实际上使代码更简单。

一个共同的理念是,职能应该有一个责任。我同意这一点。但人们认为这太过分了,并得出结论,如果一个函数有多个回报,它必须有多个责任。 (他们通过说函数永远不会超过50行,或者其他任意数字来扩展它。)我说不。仅仅因为一个函数只有一个责任,并不意味着它没有太多的事情可以实现这个责任。

以打开数据库为例。这是一个责任,但它由许多步骤组成,每个步骤都可能出错。打开连接。登录。获取连接对象&amp;把它返还。 3个步骤,每个步骤都可能失败。您可以将其分解为3个子步骤,但之后不要使用这样的代码:

int foo()
{ 
  DatabaseObject db = OpenDatabase(...);
}

你最终会得到:

int foo()
{
  Connection conn = Connect(...);
  bool login = Login(...);
  DBObj db = GetDBObj(conn);
}

所以你真的只是把假定的多个职责移到了调用堆栈的更高点。

3)原因:多个返回点不是面向对象的。     反驳:这实际上只是另一种说法,“每个人都说多重回报都很糟糕,但我真的不知道为什么。”

采取另一种方式,这实际上只是尝试将所有东西塞进一个物体形状的盒子中,即使它不属于那里。当然,也许连接是一个对象。但是登录了吗?登录尝试不是(IMO)对象。这是一个操作。或算法。试图采用这种算法并将其塞入一个对象形状的盒子是对OOP的无偿尝试,并且只会导致代码更复杂,更难维护,甚至可能效率更低。

答案 1 :(得分:8)

功能应该尽快返回。这节省了不必要的语句中的语义开销。尽快返回的函数提供最高的清晰度和最干净,最易维护的源代码。

当你必须手动编写以释放你分配的每一个资源时,SESE风​​格的代码很好,并且记住在几个不同的地方释放它们都是浪费。然而,现在我们有了RAII,它肯定是多余的。

答案 2 :(得分:3)

这纯粹是个人偏好或编码标准的问题。就个人而言,我更喜欢第三种变体:

return someCondition ? doSomething() : doSomethingElse();

答案 3 :(得分:3)

这取决于,我更喜欢FredOverflow

return someCondition ? doSomething() : doSomethingElse();

如果这足够了。如果不是,我想知道类似的情况 - 如果你有更长的代码 - 让我说30-40行或更多,我应该把return;放在一个地方,这是没有必要的。例如,请考虑以下情况:

if( cond1 )
{
    if( cond2 )
    {
         // do stuff
    }
    else if( cond3 )
    {
        // ..
    }
} 
else if( cond4 )
{
    // ..
}
else
{
    //..
}

我想知道的是 - 我应该在每个案例结尾处放置return;(在void函数中) - 这是一种好的还是坏的编码风格(因为return;是无关紧要的或不)。最后我决定把它,因为开发人员稍后会读到这段代码,知道这是一个最终状态,并且在这个函数中没有什么可以做的了。如果他/她仅在这种情况下感兴趣,不要阅读其余的代码。

答案 4 :(得分:-1)

取决于。

如果你遵循早期回报的约定来处理错误案例那么这很好,如果你只是在做任意事情那么它就是坏事。

所呈现的代码最严重的问题是你没有使用花括号。这意味着不太了解清晰度是什么。如果不是因为我只是以“目标明确”来回答您的主要问题,但首先您需要了解清晰度。作为这条道路的第一步,开始使用花括号。尝试让其他人可以阅读您的代码,以便其他人可以一目了然(或者自己月/年后)。

干杯&amp;第h。,