Оценка констант в для контура

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

В этом примере будет my_function(MY_CONSTANT) будет оцениваться на каждой итерации или будет сохраняться автоматически? Зависит ли это от используемых флагов оптимизации?

4 ответа

Решение

Он должен работать так, как будто функция вызывается каждый раз.

Однако, если компилятор может доказать, что результат функции будет одинаковым каждый раз, он может оптимизироваться в соответствии с правилом "как будто".

Например, это обычно происходит с звонками .end() для стандартных контейнеров.


Общий совет: если вы сомневаетесь, нужно ли микрооптимизировать фрагмент кода,

  1. Не делай этого.
  2. Если вы все еще думаете об этом, измерьте.
  3. Ну, был третий момент, но я забыл, может быть, все еще подожду.

Другими словами, решите, использовать ли переменную, основываясь на том, насколько ясен код, а не на воображаемой производительности.

Будет оцениваться каждая итерация. Вы можете сэкономить дополнительное время вычислений, делая что-то вроде

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

Современный оптимизирующий компилятор под as-if rule может быть в состоянии оптимизировать вызов функции в случае, который вы изложили в своем комментарии здесь. as-if rule говорит, что соответствующий компилятор только эмулирует наблюдаемое поведение, мы можем увидеть это, перейдя к черновому стандартному разделу C++ 1.9 Выполнение программы, которое говорит:

[...] Скорее соответствующие реализации должны эмулировать (только) наблюдаемое поведение абстрактной машины, как объяснено ниже.

Так что если вы используете постоянное выражение и my_function не имеет видимых побочных эффектов, которые можно было бы оптимизировать. Мы можем собрать простой тест ( увидеть его в прямом эфире на 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 ) ;
  }
}

В случае withConstant мы видим, что это оптимизирует вычисления:

cmpl    $30, %ebx   #, i

и даже в случае withoutConstant он выполняет вычисления вместо выполнения вызова функции:

leal    0(%rbp,%rbx), %eax  #, D.2605

Если my_function объявляется constexpr, а аргумент действительно является константой, значение вычисляется во время компиляции и, таким образом, соответствует правилам "как будто" и "последовательная согласованность без гонки данных".

constexpr my_function(const int c);

Если у вашей функции есть побочные эффекты, это не позволит компилятору переместить ее из for-loop так как он не будет выполнять правило "как будто", если только компилятор не сможет найти выход из него.

Компилятор может быть встроенным my_functionуменьшите его, как если бы он был частью цикла, и с постоянным сокращением выясните, что это действительно только константа, де-факто удаляющая вызов и заменяющая его константой.

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

Таким образом, ответ на ваш вопрос... возможно!

Другие вопросы по тегам