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

rub*_*nvb 19 c++ if-statement

这段代码:

if( someCondition )
    return doSomething();

return doSomethingElse();
Run Code Online (Sandbox Code Playgroud)

与此代码:

if( someCondition )
    return doSomething();
else
    return doSomethingElse();
Run Code Online (Sandbox Code Playgroud)

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

if( someCondition )
    return doSomething();
else if( someOtherCondition )
    return doSomethingDifferently();
//...
else
    return doSomethingElse();
Run Code Online (Sandbox Code Playgroud)

谢谢!

Joh*_*ing 45

当函数中有多个return语句时,这称为"提前返回".如果你在谷歌搜索 "早期返回",你会发现链接后链接说它很糟糕.

我说胡说八道.

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

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

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

...

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

你做这个:

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

提早退货不会造成资源泄漏.在大多数情况下,您甚至不需要使用,auto_ptr因为您将创建数组或字符串,在您将使用的chich情况下vector,string或类似的东西.

您应该设计这样的代码以保持稳健性,因为可能存在异常.例外是一种早期回报的形式,就像一个明确的return陈述,你需要准备好处理它们.您可能无法处理异常foo(),但foo()不应泄漏.

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

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

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

int foo()
{ 
  DatabaseObject db = OpenDatabase(...);
}
Run Code Online (Sandbox Code Playgroud)

你最终会得到:

int foo()
{
  Connection conn = Connect(...);
  bool login = Login(...);
  DBObj db = GetDBObj(conn);
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • +10即使它只让我给1 (3认同)

Pup*_*ppy 8

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

当您必须手动编写以释放已分配的每个资源时,SESE风​​格的代码很好,并且记住在几个不同的地方释放它们都是浪费.但是,现在我们有了RAII,它绝对是多余的.


Kir*_*rov 5

这取决于,我更喜欢和 FredOverflow 一样

return someCondition ? doSomething() : doSomethingElse();
Run Code Online (Sandbox Code Playgroud)

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

if( cond1 )
{
    if( cond2 )
    {
         // do stuff
    }
    else if( cond3 )
    {
        // ..
    }
} 
else if( cond4 )
{
    // ..
}
else
{
    //..
}
Run Code Online (Sandbox Code Playgroud)

我想知道的是 - 我应该return;在每个案例的末尾放置(在 void 函数中) - 这是一种好的还是坏的编码风格(因为有与没有无关紧要return;)。最后我决定放它,因为稍后会阅读此代码的开发人员知道这是一个最终状态,并且此功能不再需要执行任何操作。不要阅读其余的代码,如果他/她只在这种情况下感兴趣。