rel*_*xxx 90 c++ if-statement side-effects short-circuiting
有时,if语句可能相当复杂或冗长,因此为了便于阅读,最好在之前提取复杂的调用if.
例如:
if (SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall())
{
// do stuff
}
Run Code Online (Sandbox Code Playgroud)
进入这个
bool b1 = SomeComplicatedFunctionCall();
bool b2 = OtherComplicatedFunctionCall();
if (b1 || b2)
{
//do stuff
}
Run Code Online (Sandbox Code Playgroud)
(提供示例并不是那么糟糕,它仅用于说明...想象其他具有多个参数的调用等)
但是通过这种提取,我失去了短路评估(SCE).
Hor*_*man 118
一个自然的解决方案是这样的:
bool b1 = SomeCondition();
bool b2 = b1 || SomeOtherCondition();
bool b3 = b2 || SomeThirdCondition();
// any other condition
bool bn = bn_1 || SomeFinalCondition();
if (bn)
{
// do stuff
}
Run Code Online (Sandbox Code Playgroud)
这具有易于理解,适用于所有情况和具有短路行为的益处.
这是我最初的解决方案:方法调用和for循环体的一个好模式如下:
if (!SomeComplicatedFunctionCall())
return; // or continue
if (!SomeOtherComplicatedFunctionCall())
return; // or continue
// do stuff
Run Code Online (Sandbox Code Playgroud)
一个人获得了短路评估相同的良好性能优势,但代码看起来更具可读性.
Ami*_*ack 31
我倾向于将条件分解为多行,即:
if( SomeComplicatedFunctionCall()
|| OtherComplicatedFunctionCall()
) {
Run Code Online (Sandbox Code Playgroud)
即使在处理多个操作符(&&)时,您也只需要使用每对括号进行缩进.SCE仍在继续 - 无需使用变量.以这种方式编写代码使我多年来对它更加可读.更复杂的例子:
if( one()
||( two()> 1337
&&( three()== 'foo'
|| four()
)
)
|| five()!= 3.1415
) {
Run Code Online (Sandbox Code Playgroud)
Som*_*ude 28
如果你有很长的条件链以及如何保持一些短路,那么你可以使用临时变量来组合多个条件.举个例子,就可以做例如
bool b = SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall();
if (b && some_other_expression) { ... }
Run Code Online (Sandbox Code Playgroud)
如果你有一个支持C++ 11的编译器,你可以使用lambda表达式将表达式组合成函数,类似于上面的:
auto e = []()
{
return SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall();
};
if (e() && some_other_expression) { ... }
Run Code Online (Sandbox Code Playgroud)
SJu*_*n76 21
1)是的,你不再拥有SCE.否则,你会有
bool b1 = SomeComplicatedFunctionCall();
bool b2 = OtherComplicatedFunctionCall();
Run Code Online (Sandbox Code Playgroud)
以某种方式工作,取决于以后是否有if声明.方式太复杂了.
2)这是基于意见的,但对于相当复杂的表达式,您可以这样做:
if (SomeComplicatedFunctionCall()
|| OtherComplicatedFunctionCall()) {
Run Code Online (Sandbox Code Playgroud)
如果它过于复杂,那么显而易见的解决方案是创建一个评估表达式并调用它的函数.
KII*_*IIV 21
您还可以使用:
bool b = someComplicatedStuff();
b = b || otherComplicatedStuff(); // it has to be: b = b || ...; b |= ...; is bitwise OR and SCE is not working then
Run Code Online (Sandbox Code Playgroud)
和SCE将工作.
但它的可读性并不比例如:
if (
someComplicatedStuff()
||
otherComplicatedStuff()
)
Run Code Online (Sandbox Code Playgroud)
son*_*yao 14
1)我每次真的失去了SCE吗?编译器是否允许某些场景"优化它"并仍然提供SCE?
我不认为这种优化是允许的; 特别是OtherComplicatedFunctionCall()可能有一些副作用.
2)在这种情况下,最佳做法是什么?是否只有这种可能性(当我想要SCE时)才能直接拥有我需要的所有内容,并且"只是将其格式化为尽可能可读"?
我更喜欢将它重构为一个函数或一个具有描述性名称的变量; 这将保留短路评估和可读性:
bool getSomeResult() {
return SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall();
}
...
if (getSomeResult())
{
//do stuff
}
Run Code Online (Sandbox Code Playgroud)
当我们getSomeResult()基于SomeComplicatedFunctionCall()和实现时OtherComplicatedFunctionCall(),如果它们仍然复杂,我们可以递归地分解它们.
1)我每次真的失去了SCE吗?编译器是否允许某些场景"优化它"并仍然提供SCE?
不,你没有,但它的应用方式不同:
if (SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall())
{
// do stuff
}
Run Code Online (Sandbox Code Playgroud)
在这里,OtherComplicatedFunctionCall()如果SomeComplicatedFunctionCall()返回true ,编译器甚至不会运行.
bool b1 = SomeComplicatedFunctionCall();
bool b2 = OtherComplicatedFunctionCall();
if (b1 || b2)
{
//do stuff
}
Run Code Online (Sandbox Code Playgroud)
在这里,两个函数都将运行,因为它们必须存储在b1和中b2.b1 == true然后b2不会评估Ff (SCE).但OtherComplicatedFunctionCall()已经运行了.
如果b2在其他任何地方使用,编译器可能足够智能,如果函数没有可观察到的副作用,则内联if中的函数调用.
2)在这种情况下,最佳做法是什么?是否只有这种可能性(当我想要SCE时)才能直接拥有我需要的所有内容,并且"只是将其格式化为尽可能可读"?
那要看.您是否 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
Run Code Online (Sandbox Code Playgroud)
您可以将循环放入函数中,让函数接受条件列表并输出布尔值.