【问题标题】:Is an "if(...) return ...;" without "else" considered good style? [closed]是“如果(...)返回...;”没有“else”算好风格? [关闭]
【发布时间】:2010-11-21 13:31:10
【问题描述】:

这段代码:

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();

谢谢!

【问题讨论】:

  • 2nd 有一个不必要的 else 语句,没有条件被测试,为什么要使用它?
  • @DumbCoder:一个简单的错字...我已经修正了。
  • -1:主观,可能会引发一场激烈的战争。
  • @BalusC:天哪,我怎么会错过这个:s

标签: c++ if-statement


【解决方案1】:

当函数中有多个返回语句时,这称为“提前返回”。如果您为“提前返回”执行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 行或其他任意数字来扩展这一点。)我说不。仅仅因为一个函数只有一个职责,并不意味着它不需要做很多事情来履行这个职责。

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

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

你最终会拥有:

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

因此,您实际上只是将假定的多个职责移到调用堆栈中的更高位置。

3) 原因:多个返回点不是面向对象的。 反驳:这实际上只是另一种说法“每个人都说多次退货不好,尽管我真的不知道为什么。”

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

【讨论】:

  • +10 即使它只让我给 1
  • 虽然我确信这可以被视为个人的和模棱两可的,但我认为仅凭努力(当然我同意每一点的事实)就值得打上绿色的复选标记!
  • 但这如何回答这个问题?问题中的两种风格不是都早早回归了吗?
【解决方案2】:

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

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

【讨论】:

    【解决方案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】:

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

      return someCondition ? doSomething() : doSomethingElse();
      

      【讨论】:

      • 如果两个函数返回类型都可以转换为封闭作用域的返回类型,但彼此不相同,则三元运算符将无法编译。然后你需要一个丑陋的演员来修复它。只有当所涉及的条件很简单并且类型不太可能改变时(例如,被调用的函数在标准库中,而不是应用程序代码中),我才会在这里支持三元。
      【解决方案5】:

      视情况而定。

      如果您遵循提前返回的惯例来处理错误情况,那很好,如果您只是在做任意事情,那就不好了。

      所呈现的代码最严重的问题是您没有使用花括号。这意味着不太了解清晰度的含义。如果不是这样,我只会用“力求清晰”来回答您的主要问题,但首先您需要了解清晰度。作为这条道路的第一步,开始使用花括号。尽量让您的代码能够被其他人阅读,以便其他人(或您自己在数月/年之后)一眼就能理解。

      干杯,

      【讨论】:

      • -1:当人们抱怨省略花括号时,我讨厌它。如果您正确缩进代码,省略花括号是一个完全合理的约定,并且每个人都知道如果他们添加第二行代码,就去添加花括号。
      • 就我个人而言,我发现添加花括号会无缘无故地降低清晰度,因为它会增加视觉噪音并减少适合屏幕的功能代码量。
      • -1 声称在您喜欢的样式中不使用花括号表明缺乏对清晰性的理解
      • 这就是为什么我认为卷发是邪恶的。通过缩进对语句进行分组是更好的 imo。
      • @Johannes:您对无括号的偏好在学术界可能是有道理的。切换到 Python。 ;-)
      猜你喜欢
      • 1970-01-01
      • 2013-01-16
      • 2021-12-17
      • 2012-10-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-04
      • 1970-01-01
      相关资源
      最近更新 更多