Is it good practice to buffer the results of functions before a loop?

1.1k views Asked by At

I have the following looking code in VC++:

for (int i = (a - 1) * b; i < a * b && i < someObject->someFunction(); i++)
{
    // ...
}

As far as I know compilers optimize all these arithmetic operations and they won't be executed on each loop, but I'm not sure if they can tell that the function above also returns the same value each time and it doesn't need to be called each time.

Is it a better practice to save all calculations into variables, or just rely on compiler optimizations to have a more readable code?

int start = (a - 1) * b;
int expra = a * b;
int exprb = someObject->someFunction();
for (int i = startl i < expra && i < exprb; i++)
{
    // ...
}
6

There are 6 answers

0
thkala On BEST ANSWER

If a function resides within the same compilation unit as its caller, the compiler can often deduce some facts about it - e.g. that its output might not change for subsequent calls. In general, however, that is not the case.

In your example, assigning variables for these simple arithmetic expressions does not really change anything with regards to the produced object code and, in my opinion, makes the code less readable. Unless you have a bunch of long expressions that cannot reasonably be put within a line or two, you should avoid using temporary variables - if for no other reason, then just to reduce namespace pollution.

Using temporary variables implies a significant management overhead for the programmer, in order to keep them separate and avoid unintended side-effects. It also makes reusing code snippets harder.

On the other hand, assigning the result of the function to a variable can help the compiler optimise your code better by explicitly avoiding multiple function calls.

Personally, I would go with this:

int expr = someObject->someFunction();
for (int i = (a - 1) * b; i < a * b && i < expr; i++)
{
    // ...
}
0
sharptooth On

From my experience VC++ compiler won't optimize the function call out unless it can see the function implementation at the point of compiling the calling code. So moving the call outside the loop is a good idea.

2
Jon Purdy On

Short answer: it depends. If the compiler can deduce that running someObject->someFunction() every time and caching the result once both produce the same effects, it is allowed (but not guaranteed) to do so. Whether this static analysis is possible depends on your program: specifically, what the static type of someObject is and what its dynamic type is expected to be, as well as what someFunction() actually does, whether it's virtual, and so on.

In general, if it only needs to be done once, write your code in such a way that it can only be done once, bypassing the need to worry about what the compiler might be doing:

int start = (a - 1) * b;
int expra = a * b;
int exprb = someObject->someFunction();
for (int i = start; i < expra && i < exprb; i++)
    // ...

Or, if you're into being concise:

for (int i = (a - 1) * b, expra = a * b, exprb = someObject->someFunction();
     i < expra && i < exprb; i++)
    // ...
0
Greg On

The compiler cannot make any assumption on whether your function will return the same value at each time. Let's imagine that your object is a socket, how could the compiler possibly know what will be its output?

Also, the optimization that a compiler can make in such loops strongly depends on the whether a and b are declared as const or not, and whether or not they are local. With advanced optimization schemes, it may be able to infer that a and b are neither modified in the loop nor in your function (again, you might imagine that your object holds some reference to them).

Well, in short: go for the second version of your code!

1
Laurent G On

It is very likely that the compiler will call the function each time.

If you are concerned with the readability of code, what about using:

int maxindex = min (expra, exprb);
for (i=start; i<maxindex; i++)

IMHO, long lines does not improve readability.

Writing short lines and doing multiple step to get a result, does not impact the performance, this is exactly why we use compilers.

0
CashCow On

Effectively what you might be asking is whether the compiler will inline the function someFunction() and whether it will see that someObject is the same instance in each loop, and if it does both it will potentially "cache" the return value and not keep re-evaluating it.

Much of this may depend on what optimisation settings you use, with VC++ as well as any other compiler, although I am not sure VC++ gives you quite as many flags as gnu.

I often find it incredible that programmers rely on compilers to optimise things they can easily optimise themselves. Just move the expression to the first section of the for-loop if you know it will evaluate the same each time:

Just do this and don't rely on the compiler:

for (int i = (a - 1) * b, iMax = someObject->someFunction();
       i < a * b && i < iMax; ++i) 
{
  // body
}