Оптимизация — Являются ли параметры const и переменные класса пессимизацией?

Я пытаюсь выяснить, когда const следует использовать при написании кода C ++. Это все примеры пессимизации или так полезно писать код ?:

Пример 1:

int findVal(const int OTHER_VAL) const
{
switch(OTHER_VAL)
{
case 1:
return 2;
default:
return 3;
}
}

Пример 2:

enum class MobType
{
COW, CHICKEN, DOG, PIG
};

class BaseMob
{
protected:
BaseMob(const MobType TYPE) : TYPE(TYPE) { }

const MobType TYPE;
};

Пример 3:

void showWorld(const World &world)
{
auto data = world.getData();
for (auto &i:data)
i.print();
}

0

Решение

Нет, это не так.

const Локальные переменные с автоматическим хранением (включая аргументы функций) являются чисто синтаксическим сахаром, помогающим программистам-людям устанавливать правила для своего кода. Это не помогает оптимизатору вообще. Оптимизирующие компиляторы извлекают необходимое перемещение данных из источника C и оптимизируют его. Как правило, им все равно, если вы повторно используете одну и ту же переменную tmp для множества разных вещей или у вас есть 10 разных const tmp1 = a+10; в той же функции.

И да, это относится к аргументам функции, переданным по значению; это локальные переменные с автоматическим хранением, передаваемые в регистрах или в стеке. И нет, это не означает, что вызывающая сторона может предположить, что функция не модифицировала стековую память, используемую для передачи аргументов, поэтому Помогите оптимизатора тоже много. (Выполнение второго вызова функции с теми же аргументами все еще требует перезаписи аргументов в стек (если не все аргументы помещаются в регистры), потому что const Аргумент arg не меняет того факта, что вызываемая функция «владеет» этим пространством стека и может использовать его как пустое место, как захочет.)


const на статические / глобальные / ссылочные переменные помогает. static const int foo = 10; может быть встроен как непосредственная константа вместо загрузки из памяти. (например. add eax, 10 вместо add eax, [foo]).


С помощью const пометить метод класса как не меняющий членов класса может также помочь компилятору избежать повторной загрузки членов класса после вызова функции. (т.е. держать их вживую в регистрах). Это в основном применимо только в том случае, если компилятор не может увидеть определение функции, в противном случае хороший оптимизирующий компилятор может просто посмотреть на то, что делает вызываемая функция, и соответственно оптимизировать. (Пока это не в библиотеке Unix, где символьное расположение означает, что он не может предположить, что вызванная функция, которую он видит во время компиляции, будет вызвана после динамического связывания.)

3

Другие решения

Всякий раз, когда вы логически не изменяете значение или объект, вы должны сделать это const, Логически я имею в виду не каждый раз, когда вам это технически разрешено, но каждый раз, когда это логично в контексте ваших функций, классов и кода.

Простым примером может быть простая функция «get», как видно в примере 1, эти функции не должны изменять состояние класса, и поэтому должны быть помечены как постоянные, поскольку это поможет документировать ваше намерение для пользователя, а также поможет вам обеспечить инвариантность класса.

Существуют ситуации, когда имеет смысл создать неизменный объект, как показано в примере 2. Мы не так часто видим их в C ++, но многие другие языки часто их используют. Если он не добавляет никакого значения, чтобы иметь возможность изменять определенный элемент в течение времени жизни объекта, вы можете также сделать его константой.

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

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

Это также то, почему работа вокруг константы (например) const_cast литье, которое можно отбросить const, может привести к некоторому нежелательному поведению. В качестве примера проверьте следующее:

#include <stdio.h>

static const int foo = 10;

int constsum(void) {
return foo + 5;
}

int main(int argc, char* argv[]) {
int a = constsum();
int* newFoo = const_cast<int*>(&foo);
*newFoo = 20;
int b = constsum();
printf("%d\n", a + b);
return 0;
}

Как видно из этого примера (увидеть код здесь) это может не дать желаемого результата, так как результат кода в 30 быть напечатанным, а не как ожидалось 40.

При осмотре произведенной сборки видно почему (составлен в сборку):

constsum():
mov     eax, 15
ret
main:
mov     eax, 30
ret

Компилятор просто вставляет значения, так как он может видеть, что они постоянны, он не заботится о том, чтобы const_cast используется.

Так что const правильность и использование const это ценный инструмент, который может повысить производительность и стабильность вашего кода, но также (и не забывать) помогает документировать ваш код.

3

По вопросам рекламы [email protected]