if 문-단락 평가 대 가독성
때로는 if
문이 다소 복잡하거나 길 수 있으므로 가독성을 위해 복잡한 호출을 먼저 추출하는 것이 좋습니다 if
.
예 :
if (SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall())
{
// do stuff
}
이것으로
bool b1 = SomeComplicatedFunctionCall();
bool b2 = OtherComplicatedFunctionCall();
if (b1 || b2)
{
//do stuff
}
(제공되는 예는없는 것을 여러 인수 등 다른 통화를 상상 ... 그냥 그림을 위해이다, 나쁜)
그러나이 추출로 단락 평가 (SCE)를 잃었습니다.
- 매번 SCE를 잃게 되나요? 컴파일러가 "최적화"하고 여전히 SCE를 제공 할 수있는 시나리오가 있습니까?
- SCE를 잃지 않고 두 번째 스 니펫의 향상된 가독성을 유지할 수있는 방법이 있습니까?
하나의 자연스러운 해결책은 다음과 같습니다.
bool b1 = SomeCondition();
bool b2 = b1 || SomeOtherCondition();
bool b3 = b2 || SomeThirdCondition();
// any other condition
bool bn = bn_1 || SomeFinalCondition();
if (bn)
{
// do stuff
}
이것은 이해하기 쉽고 모든 경우에 적용 할 수 있으며 단락 동작이 있다는 이점이 있습니다.
이것이 나의 초기 솔루션이었습니다. 메소드 호출과 for-loop 본문의 좋은 패턴은 다음과 같습니다.
if (!SomeComplicatedFunctionCall())
return; // or continue
if (!SomeOtherComplicatedFunctionCall())
return; // or continue
// do stuff
하나는 단락 평가와 동일한 성능 이점을 얻지 만 코드가 더 읽기 쉬워 보입니다.
조건을 여러 줄로 나누는 경향이 있습니다.
if( SomeComplicatedFunctionCall()
|| OtherComplicatedFunctionCall()
) {
여러 연산자 (&&)를 다룰 때에도 각 대괄호 쌍으로 들여 쓰기 만하면됩니다. SCE는 여전히 시작됩니다-변수를 사용할 필요가 없습니다. 이런 식으로 코드를 작성하면 이미 몇 년 동안 더 쉽게 읽을 수있게되었습니다. 더 복잡한 예 :
if( one()
||( two()> 1337
&&( three()== 'foo'
|| four()
)
)
|| five()!= 3.1415
) {
긴 조건 체인이 있고 단락을 유지해야 할 항목이있는 경우 임시 변수를 사용하여 여러 조건을 결합 할 수 있습니다. 예를 들어 다음과 같이 할 수 있습니다.
bool b = SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall();
if (b && some_other_expression) { ... }
If you have a C++11 capable compiler you could use lambda expressions to combine expressions into functions, similar to the above:
auto e = []()
{
return SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall();
};
if (e() && some_other_expression) { ... }
1) Yes, you no longer have SCE. Otherwise, you would have that
bool b1 = SomeComplicatedFunctionCall();
bool b2 = OtherComplicatedFunctionCall();
works one way or the other depending if there is an if
statement later. Way too complex.
2) This is opinion based, but for reasonably complex expressions you can do:
if (SomeComplicatedFunctionCall()
|| OtherComplicatedFunctionCall()) {
If it ways too complex, the obvious solution is to create a function that evaluates the expression and call it.
You can also use:
bool b = someComplicatedStuff();
b = b || otherComplicatedStuff(); // it has to be: b = b || ...; b |= ...; is bitwise OR and SCE is not working then
and SCE will work.
But it's not much more readable than for example:
if (
someComplicatedStuff()
||
otherComplicatedStuff()
)
1) Do I really lose SCE every time? Is compiler is some scenario allowed to "optimize it" and still provide SCE?
I don't think such optimization is allowed; especially OtherComplicatedFunctionCall()
might have some side effects.
2) What is the best practice in such situation? Is it only possibility (when I want SCE) to have all I need directly inside if and "just format it to be as readable as possible" ?
I prefer to refactor it into one function or one variable with a descriptive name; which will preserve both short circuit evaluation and readability:
bool getSomeResult() {
return SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall();
}
...
if (getSomeResult())
{
//do stuff
}
And as we implement getSomeResult()
based on SomeComplicatedFunctionCall()
and OtherComplicatedFunctionCall()
, we could decompose them recursively if they're still complicated.
1) Do I really lose SCE every time? Is compiler is some scenario allowed to "optimize it" and still provide SCE?
No you don't, but it's applied differently:
if (SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall())
{
// do stuff
}
Here, the compiler won't even run OtherComplicatedFunctionCall()
if SomeComplicatedFunctionCall()
returns true.
bool b1 = SomeComplicatedFunctionCall();
bool b2 = OtherComplicatedFunctionCall();
if (b1 || b2)
{
//do stuff
}
Here, both functions will run because they have to be stored into b1
and b2
. Ff b1 == true
then b2
won't be evaluated (SCE). But OtherComplicatedFunctionCall()
has been run already.
If b2
is used nowhere else the compiler might be smart enough to inline the function call inside the if if the function has no observable side-effects.
2) What is the best practice in such situation? Is it only possibility (when I want SCE) to have all I need directly inside if and "just format it to be as readable as possible" ?
That depends. Do you need OtherComplicatedFunctionCall()
to run because of side-effects or the performance hit of the function is minimal then you should use the second approach for readability. Otherwise, stick to SCE through the first approach.
Another possibility that short circuits and has the conditions in one place:
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
You could put the loop into a function and let the function accept a list of conditions and output a boolean value.
Very strange: you are talking about readability when nobody mentions the usage of comment within the code:
if (somecomplicated_function() || // let me explain what this function does
someother_function()) // this function does something else
...
In top of that, I always preceed my functions with some comments, about the function itself, about its input and output, and sometimes I put an example, as you can see here:
/*---------------------------*/
/*! 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)
Obviously the formatting to use for your comments may depend on your development environment (Visual studio, JavaDoc under Eclipse, ...)
As far as SCE is concerned, I assume by this you mean the following:
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) {
...
}
Readability is necessary if you work in a company and your code will be read by someone else. If you write a program for yourself, it is up to you if you want to sacrifice performance for the sake of comprehensible code.
참고URL : https://stackoverflow.com/questions/40081279/if-statement-short-circuit-evaluation-vs-readability
'development' 카테고리의 다른 글
조건부 변수 대 세마포 (0) | 2020.09.04 |
---|---|
Google API를 통해 사용자 정보 얻기 (0) | 2020.09.04 |
부트 스트랩에는 여전히 외부 지원이 필요합니다. (0) | 2020.09.03 |
ACTION_SEND를 통해 Android 앱에서 Facebook에 텍스트 공유 (0) | 2020.09.03 |
mongodb 여러 배열 항목으로 찾기 (0) | 2020.09.03 |