Reputation: 3
I have a C++ code that looks like this:
int A = 1;
int B = 1;
for(int i=0; i<100; ++i) {
if(A==1) {
doA();
}
if(B==1) {
doB();
}
doC();
}
I know it hurts performance to place conditions inside a loop. It would be good to move these conditons out of it. However, if I do that I will have to rewrite the function 4 times here (for combinations of A
and B
).
What would be a good way to get the performance and write less code? Is using an empty function worth it, performance-wise? How should I duplicate a function that has the exact type of doA()
but does nothing?
Upvotes: 0
Views: 141
Reputation: 238301
[How] to avoid if-conditional inside of a loop?
If none of the functions modify A
or B
, then you can move the condition to the outside of the loop:
if (A==1 && B==1) {
for(int i=0; i<100; ++i) {
doA();
doB();
doC();
}
} else if(A==1) {
for(int i=0; i<100; ++i) {
doA();
doC();
}
} else if(B==1) {
for(int i=0; i<100; ++i) {
doB();
doC();
}
} else {
for(int i=0; i<100; ++i) {
doC();
}
}
If the order of the function calls do not matter, then you can simplify:
if (A==1 && B==1) {
for(int i=0; i<100; ++i) {
doA();
doB();
}
} else if(A==1) {
for(int i=0; i<100; ++i) {
doA();
}
} else if(B==1) {
for(int i=0; i<100; ++i) {
doB();
}
}
for(int i=0; i<100; ++i) {
doC();
}
I know it hurts performance to place condition inside a loop.
It can. On the other hand, it doesn't necessarily hurt performance at all. Hoisting of loop invariants is a fairly standard compiler optimisation. If the compiler thinks it is faster and can prove that it doesn't change the behaviour, then it may do the transformation automatically.
Even if the compiler does not do the optimisation, it is possible that the performance cost is insignificant.
However, if I do that I will have to rewrite functions 4 times here (with combinations of calling function A/B).
This is true, and is a good argument to avoid manually hoisting the condition to the outside of the loop. On the other hand, the function is quite simple so there is not much to rewrite, as demonstrated.
What would be a good way to get the performance ...
What you've written is probably good. You can compare measurements with the explicit hoisting and see if improves at all. If it does, then consider whether the improvement is worth the added complexity.
What would be a good way to ... write fewer code?
What you've written is fairly optimal.
Upvotes: 1
Reputation: 45654
Well, if the compiler can prove that the conditions are invariant over the loop, it should hoist them out of it with even moderate optimization. Even if it doesn't though, are you sure that's significant? Anyway, for more complex cases, especially if escape-analysis isn't that trivial, assigning them to a flag before the loop and then using that might give it the push needed.
Rarely should you hoist it yourself, but if you insist, lambdas are wonderful:
auto f = [&](auto a, auto b){
for (int i = 0; i < 100; ++i) {
if constexpr (a)
doA();
if constexpr (b)
doB();
doC();
}
};
if (A == 1 && B == 1)
f(std::true_type(), std::true_type());
else if (A == 1)
f(std::true_type(), std::false_type());
else if (B == 1)
f(std::false_type(), std::true_type());
else
f(std::false_type(), std::false_type());
Upvotes: 0
Reputation: 143
In general, if you think that your code is badly designed and you need to rewrite the code, from my experience it is best to simply rewrite the code. Addressing the body of your question, if statements don't really hurt performance. Try fixing the algorithm instead, if you notice some issues. A different aspect of the question is code complexity (how complex the code look). Switch case is (for the most part) easier on the eye.
I don't really understand the third part of your question, the part about empty functions. Explain more in the comments or edit the question.
Upvotes: 0