Может ли добавление константы в указатель помочь оптимизации?
У меня есть указатель 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
Вы не говорите, какой компилятор вы используете. Но если вы читаете и записываете в память, вы можете воспользоваться "ограничением" или похожим. Компилятор не знает, имеют ли ваши указатели псевдонимы одну и ту же память, поэтому любой магазин часто заставляет снова загружать другие значения. "Ограничить" сообщает компилятору, что никакого наложения указателя не происходит, и он может продолжать использовать значения, загруженные до последующей записи. Другой способ избежать проблемы с псевдонимом - загрузить ваши значения в локальные переменные, после чего компилятор не будет перезагружен после записи.