if statement - 短路评估与可读性

时间:2016-10-17 08:03:18

标签: c++ if-statement short-circuiting side-effects

有时,if语句可能相当复杂或冗长,因此为了便于阅读,最好在if之前提取复杂的调用。

e.g。这样:

if (SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall())
{
    // do stuff
}

进入这个

bool b1 = SomeComplicatedFunctionCall();
bool b2 = OtherComplicatedFunctionCall();

if (b1 || b2)
{
    //do stuff
}

(例如, 错误,它仅用于说明...想象具有多个参数的其他调用等。)

但是通过这次提取,我失去了短路评估(SCE)。

  1. 我每次真的失去了SCE吗?是否存在允许编译器“优化”并仍然提供SCE的情况?
  2. 有没有办法在不丢失SCE的情况下保持第二个片段的可读性?

10 个答案:

答案 0 :(得分:118)

一个自然的解决方案如下:

bool b1 = SomeCondition();
bool b2 = b1 || SomeOtherCondition();
bool b3 = b2 || SomeThirdCondition();
// any other condition
bool bn = bn_1 || SomeFinalCondition();

if (bn)
{
  // do stuff
}

这具有易于理解,适用于所有情况和短路行为的好处。

这是我最初的解决方案:方法调用和for循环体的一个好模式如下:

if (!SomeComplicatedFunctionCall())
   return; // or continue

if (!SomeOtherComplicatedFunctionCall())
   return; // or continue

// do stuff

获得短路评估相同的良好性能优势,但代码看起来更具可读性。

答案 1 :(得分:31)

我倾向于将条件分解为多行,即:

if( SomeComplicatedFunctionCall()
 || OtherComplicatedFunctionCall()
  ) {

即使处理多个操作员(&&),您也只需要使用每对支架进行缩进。 SCE仍在继续 - 无需使用变量。以这种方式编写代码使我多年来对它更加可读。更复杂的例子:

if( one()
 ||( two()> 1337
  &&( three()== 'foo'
   || four()
    )
   )
 || five()!= 3.1415
  ) {

答案 2 :(得分:28)

如果你有很长的条件链以及如何保持一些短路,那么你可以使用临时变量来组合多个条件。举个例子,就可以做到这一点。

bool b = SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall();
if (b && some_other_expression) { ... }

如果您有一个支持C ++ 11的编译器,您可以使用lambda expressions将表达式组合到函数中,类似于上面的内容:

auto e = []()
{
    return SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall();
};

if (e() && some_other_expression) { ... }

答案 3 :(得分:21)

1)是的,你不再拥有SCE。否则,你会有那个

bool b1 = SomeComplicatedFunctionCall();
bool b2 = OtherComplicatedFunctionCall();

以某种方式工作,具体取决于以后是否有if语句。方式太复杂了。

2)这是基于意见的,但对于相当复杂的表达,你可以这样做:

if (SomeComplicatedFunctionCall()
    || OtherComplicatedFunctionCall()) {

如果它过于复杂,那么显而易见的解决方案是创建一个评估表达式并调用它的函数。

答案 4 :(得分:21)

您也可以使用:

bool b = someComplicatedStuff();
b = b || otherComplicatedStuff(); // it has to be: b = b || ...;  b |= ...; is bitwise OR and SCE is not working then 

和SCE将会有效。

但它的可读性并不比例如:

if (
    someComplicatedStuff()
    ||
    otherComplicatedStuff()
   )

答案 5 :(得分:14)

  

1)我每次真的失去了SCE吗?编译器是否允许某些情况"优化它"并仍然提供SCE?

我不认为允许这样的优化;特别是OtherComplicatedFunctionCall()可能会产生一些副作用。

  

2)在这种情况下,最佳做法是什么?只有这种可能性(当我想要SCE时)才能直接拥有我需要的所有内容,如果和"只是将其格式化为尽可能可读" ?

我更喜欢将它重构为一个函数或一个带有描述性名称的变量;这将保留短路评估和可读性:

bool getSomeResult() {
    return SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall();
}

...

if (getSomeResult())
{
    //do stuff
}

当我们根据getSomeResult()SomeComplicatedFunctionCall()实施OtherComplicatedFunctionCall()时,如果它们仍然复杂,我们可以递归地对它们进行分解。

答案 6 :(得分:9)

  

1)我每次真的失去了SCE吗?编译器是某种情况   允许“优化它”并仍然提供SCE?

不,你没有,但它的应用方式不同:

if (SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall())
{
    // do stuff
}

此处,如果OtherComplicatedFunctionCall()返回true,编译器甚至不会运行SomeComplicatedFunctionCall()

bool b1 = SomeComplicatedFunctionCall();
bool b2 = OtherComplicatedFunctionCall();

if (b1 || b2)
{
    //do stuff
}

此处,两个函数运行,因为它们必须存储在b1b2中。 Ff b1 == true然后b2将不会被评估(SCE)。但是OtherComplicatedFunctionCall()已经运行了。

如果在其他任何地方使用b2,编译器可能足够智能,如果函数没有可观察到的副作用,则内联if中的函数调用。

  

2)在这种情况下,最佳做法是什么?这只是可能性吗?   (当我想要SCE时)如果和“只是   将其格式化为尽可能可读“?

这取决于。 您是否需要 OtherComplicatedFunctionCall()因为副作用或者该功能的性能损失最小,那么您应该使用第二种方法来提高可读性。否则,通过第一种方法坚持SCE。

答案 7 :(得分:8)

短路并在一个地方具备条件的另一种可能性:

bool (* conditions [])()= {&a, &b, ...}; // list of conditions
bool conditionsHold = true;
for(int i= 0; i < sizeOf(conditions); i ++){
     if (!conditions[i]()){;
         conditionsHold = false;
         break;
     }
}
//conditionsHold is true if all conditions were met, otherwise false

您可以将循环放入函数中,让函数接受条件列表并输出布尔值。

答案 8 :(得分:4)

非常奇怪:当你没有提到代码中注释的使用时,你在谈论可读性:

if (somecomplicated_function() || // let me explain what this function does
    someother_function())         // this function does something else
...

除此之外,我总是在函数前面加上一些注释,关于函数本身,关于它的输入和输出,有时候我举一个例子,你可以在这里看到:

/*---------------------------*/
/*! interpolates between values
* @param[in] X_axis : contains X-values
* @param[in] Y_axis : contains Y-values
* @param[in] value  : X-value, input to the interpolation process
* @return[out]      : the interpolated value
* @example          : interpolate([2,0],[3,2],2.4) -> 0.8
*/
int interpolate(std::vector<int>& X_axis, std::vector<int>& Y_axis, int value)

显然,用于评论的格式可能取决于您的开发环境(Visual Studio,Eclipse下的JavaDoc,......)

就SCE而言,我认为你的意思是:

bool b1;
b1 = somecomplicated_function(); // let me explain what this function does
bool b2 = false;
if (!b1) {                       // SCE : if first function call is already true,
                                 // no need to spend resources executing second function.
  b2 = someother_function();     // this function does something else
}

if (b1 || b2) {
...
}

答案 9 :(得分:-6)

如果您在公司工作并且您的代码将被其他人阅读,那么可读性是必要的。如果你为自己编写一个程序,那么如果你想为了易于理解的代码而牺牲性能,那就取决于你。