Может ли добавление константы в указатель помочь оптимизации?

У меня есть указатель int* p и выполняю некоторые операции в цикле. Я не изменяю память, просто прочитал. Если я добавлю const к указателю (оба случая, const int* p и int* const p), может ли он помочь компилятору оптимизировать код?

Я знаю другие достоинства const, такие как безопасность или самостоятельная документация, я спрашиваю об этом конкретном случае. Перефразируя вопрос: может ли const предоставить компилятору любую полезную (для оптимизации) информацию, когда-либо?

Ответы

Ответ 1

Хотя это явно специфично для реализации, трудно понять, как изменение указателя от int* до int const* могло когда-либо предоставлять какую-либо дополнительную информацию, которую компилятор не знал бы иначе.

В обоих случаях указанное значение может меняться во время выполнения цикла.

Поэтому, вероятно, это не поможет компилятору оптимизировать код.

Ответ 2

Нет. Использование const подобно этому не даст компилятору никакой информации, которая может быть использована для оптимизации.

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

Трава Саттер покрывает это больше глубины в одном из его столбцов Guru of the Week.

Ответ 3

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

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

Ответ 4

Я думаю, что компилятор не может многое сделать в вашем сценарии. Тот факт, что ваш указатель, объявленный как const int * const p, не гарантирует, что память не может быть изменена извне, например. другим потоком. Поэтому компилятор должен сгенерировать код, который считывает значение памяти на каждой итерации вашего цикла.

Но если вы не собираетесь писать в ячейку памяти, и вы знаете, что никакой другой части кода не будет, тогда вы можете создать локальную переменную и использовать ее аналогично этому:

const int * p = ...
...
int val = *p;
/* use the value in a loop */
for (i = 0; i < BAZILLION; i++)
{
    use_value(val);
}

Не только вы помогаете потенциальным читателям вашего кода видеть, что val не изменяется в цикле, но вы также даете компилятору возможность оптимизировать (например, load val в регистре).

Ответ 5

Использование const, как все говорят, вряд ли поможет компилятору оптимизировать ваш цикл.

Он может, однако, помочь оптимизировать код вне цикла или на сайте вызова метода const-qual или функции, принимающей аргументы const.

Вероятно, это зависит от того, сможет ли компилятор доказать, что он позволяет устранить избыточные нагрузки, перемещать их или вычислять значения кэша, а не пересчитывать их.

Единственный способ доказать это - это по-прежнему профилировать и/или проверять сборку, но там, где вы, вероятно, должны выглядеть.

Ответ 6

Вы не говорите, какой компилятор вы используете. Но если вы читаете и записываете в память, вы можете воспользоваться "ограничением" или похожим. Компилятор не знает, имеют ли ваши указатели псевдонимы одну и ту же память, поэтому любой магазин часто заставляет снова загружать другие значения. "Ограничить" сообщает компилятору, что никакого наложения указателя не происходит, и он может продолжать использовать значения, загруженные до последующей записи. Другой способ избежать проблемы с псевдонимом - загрузить ваши значения в локальные переменные, после чего компилятор не будет перезагружен после записи.