如果说明 – 短路评估与可读性

有时, if语句可能相当复杂或冗长,所以为了可读性,最好在if之前提取复杂的调用。

例如:

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

进入这个

 bool b1 = SomeComplicatedFunctionCall(); bool b2 = OtherComplicatedFunctionCall(); if (b1 || b2) { //do stuff } 

(提供的例子不是那么糟糕,只是为了说明…想象其他多个参数的调用等)

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

  1. 我真的每次都失去SCE吗? 是否有一些情况下编译器被允许“优化”,仍然提供SCE?
  2. 有没有方法保持第二个片段的可读性不会丢失SCE?

一个自然的解决scheme将如下所示:

 bool b1 = SomeCondition(); bool b2 = b1 || SomeOtherCondition(); bool b3 = b2 || SomeThirdCondition(); // any other condition bool bn = bn_1 || SomeFinalCondition(); if (bn) { // do stuff } 

这具有容易理解的优点,适用于所有情况并具有短路行为。


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

 if (!SomeComplicatedFunctionCall()) return; // or continue if (!SomeOtherComplicatedFunctionCall()) return; // or continue // do stuff 

人们可以从短路评估中获得相同的性能好处,但代码看起来更具可读性。

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

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

即使在处理多个操作符(&&)时,也只需要使用每一对括号来提前缩进。 SCE仍然在踢 – 不需要使用variables。 以这种方式编写代码使得它多年来对我来说更加可读。 更复杂的例子:

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

如果你有很长的条件链和什么保持一些短路,那么你可以使用临时variables来结合多个条件。 以你的榜样为例,这将是可能的

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

如果你有一个支持C ++ 11的编译器,你可以使用lambdaexpression式将expression式合并到函数中,类似于上面的代码:

 auto e = []() { return SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall(); }; if (e() && some_other_expression) { ... } 

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

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

如果以后有if语句,则以某种方式工作。 太复杂了

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

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

如果方法太复杂,那么显而易见的解决scheme是创build一个函数来评估expression式并调用它。

你也可以使用:

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

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

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

2)这种情况下的最佳做法是什么? 是否只有可能性(当我要SCE时)才有我需要的所有内容?如果“只是将其格式化为尽可能可读”?

我更愿意将它重构为一个函数或一个描述性名称的variables; 这将保持短路评估和可读性:

 bool getSomeResult() { return SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall(); } ... if (getSomeResult()) { //do stuff } 

而当我们基于SomeComplicatedFunctionCall()OtherComplicatedFunctionCall() ,如果它们仍然复杂,我们可以recursion地分解它们。

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

不,你不这样做,

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

在这里,如果SomeComplicatedFunctionCall()返回true,编译器甚至不会运行OtherComplicatedFunctionCall()

 bool b1 = SomeComplicatedFunctionCall(); bool b2 = OtherComplicatedFunctionCall(); if (b1 || b2) { //do stuff } 

在这里,两个函数都会运行,因为它们必须存储在b1b2 。 如果b1 == true那么b2将不被评估(SCE)。 但是OtherComplicatedFunctionCall()已经运行了。

如果b2在其他地方使用,那么编译器可能足够聪明,以便在if函数没有可观察的副作用的情况下内联函数调用。

2)这种情况下的最佳做法是什么? 是否只有可能性(当我要SCE时)才有我需要的所有内容?如果“只是将其格式化为尽可能可读”?

那要看。 您是否需要使用 OtherComplicatedFunctionCall()来执行副作用或者函数的性能OtherComplicatedFunctionCall()是最小的,那么您应该使用第二种方法来提高可读性。 否则,通过第一种方法坚持SCE。

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

 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 

你可以把循环放到一个函数中,让函数接受一个条件列表并输出一个布尔值。

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

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

最重要的是,我总是在我的函数前面加上一些注释,关于函数本身,关于它的input和输出,有时我会举一个例子,如下所示:

 /*---------------------------*/ /*! 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) { ... } 

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