2
for(int i = 0; i < my_function(MY_CONSTANT); ++i){
    //code using i
}

In this example, will my_function(MY_CONSTANT) be evaluated at each iteration, or will it be stored automatically? Would this depend on the optimization flags used?

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
Learning is a mess
  • 7,479
  • 7
  • 35
  • 71
  • 4
    will be evaluated at each iteration. Better to store it as a variable. – lakshmen Oct 14 '14 at 14:10
  • 1
    possible duplicate of [loop condition evaluation](http://stackoverflow.com/questions/1242185/loop-condition-evaluation) – SirGuy Oct 14 '14 at 14:11
  • 1
    @guygree, not a duplicate, no function call there. – Basilevs Oct 14 '14 at 14:18
  • @Basilevs, I don't think that changes things here, the expression (whatever that expression is) needs to be re-evaluated each time. In particular [this](http://stackoverflow.com/a/1242208/1277769) answer sums it up nicely I think – SirGuy Oct 14 '14 at 14:21
  • Still, original questions are radically different. – Basilevs Oct 14 '14 at 14:23

4 Answers4

10

It has to work as if the function is called each time.

However, if the compiler can prove that the function result will be the same each time, it can optimize under the “as if” rule.

E.g. this usually happens with calls to .end() for standard containers.


General advice: when in doubt about whether to micro-optimize a piece of code,

  1. Don't do it.
  2. If you're still thinking of doing it, measure.
  3. Well there was a third point but I've forgetting, maybe it was, still wait.

In other words, decide whether to use a variable based on how clear the code then is, not on imagined performance.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • Thank for the additional advice. When I was writing my question I had in mind that `MY_CONSTANT` was predefined by a '#define` instruction and reading the question tied above to my own, it seems that a recent compiler would store it. Many thanks! – Learning is a mess Oct 14 '14 at 14:17
3

It will be evaluated each iteration. You can save the extra computation time by doing something like

const int stop = my_function(MY_CONSTANT);
for(int i = 0; i < stop; ++i){
    //code using i
}
Cory Kramer
  • 114,268
  • 16
  • 167
  • 218
2

A modern optimizing compiler under the as-if rule may be able to optimize away the function call in the case that you outlined in your comment here. The as-if rule says that conforming compiler only has the emulate the observable behavior, we can see this by going to the draft C++ standard section 1.9 Program execution which says:

[...]Rather, conforming implementations are required to emulate (only) the observable behavior of the abstract machine as explained below.5

So if you are using a constant expression and my_function does not have observable side effects it could be optimized out. We can put together a simple test (see it live on godbolt):

#include <stdio.h>

#define blah 10

int func( int x )
{
  return x + 20 ;
}

void withConstant( int y )
{
  for(int i = 0; i < func(blah); i++)
  {
    printf("%d ", i ) ;
  }
}

void withoutConstant(int y)
{
  for(int i = 0; i < func(i+y); i++)
  {
    printf("%d ", i ) ;
  }
}

In the case of withConstant we can see it optimizes the computation:

cmpl    $30, %ebx   #, i

and even in the case of withoutConstant it inlines the calculation instead of performing a function call:

leal    0(%rbp,%rbx), %eax  #, D.2605
Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
1

If my_function is declared constexpr and the argument is really a constant, the value is calculated at compile time and thereby fulfilling the "as-if" and "sequential-consistency with no data-race" rule.

constexpr my_function(const int c);

If your function has side effects it would prevent the compiler from moving it out of the for-loop as it would not fulfil the "as-if" rule, unless the compiler can reason its way out of it.

The compiler might inline my_function, reduce on it as if it was part of the loop and with constant reduction find out that its really only a constant, de-facto removing the call and replacing it with a constant.

int my_function(const int c) {
    return 17+c; // inline and constant reduced to the value.
}

So the answer to your question is ... maybe!

Surt
  • 15,501
  • 3
  • 23
  • 39