Оценка констант в для контура
for(int i = 0; i < my_function(MY_CONSTANT); ++i){
//code using i
}
В этом примере будет my_function(MY_CONSTANT)
будет оцениваться на каждой итерации или будет сохраняться автоматически? Зависит ли это от используемых флагов оптимизации?
4 ответа
Он должен работать так, как будто функция вызывается каждый раз.
Однако, если компилятор может доказать, что результат функции будет одинаковым каждый раз, он может оптимизироваться в соответствии с правилом "как будто".
Например, это обычно происходит с звонками .end()
для стандартных контейнеров.
Общий совет: если вы сомневаетесь, нужно ли микрооптимизировать фрагмент кода,
- Не делай этого.
- Если вы все еще думаете об этом, измерьте.
- Ну, был третий момент, но я забыл, может быть, все еще подожду.
Другими словами, решите, использовать ли переменную, основываясь на том, насколько ясен код, а не на воображаемой производительности.
Будет оцениваться каждая итерация. Вы можете сэкономить дополнительное время вычислений, делая что-то вроде
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.
}
Таким образом, ответ на ваш вопрос... возможно!