Вот то, что я имею в виду, предполагаю, что у меня есть код как:
for (int i = 0; i < 1000; i++) {
char* ptr = something;
/*
... use ptr here
*/
}
Это кажется этим char* ptr
выделяется каждый раз в цикле, делая это неэффективным?
Действительно ли более эффективно записать это?
char* ptr = something;
for (int i = 0; i < 1000; i++) {
/*
... use ptr here
*/
}
Прокомментируйте эту интересную проблему.Спасибо!
Спасибо, Boda Cydo.
Это может повлиять на производительность, но многие оптимизирующие компиляторы при необходимости проводят эту оптимизацию за вас. Это называется « движение кода с инвариантным циклом ».
Вы должны зарегистрироваться и убедиться в этом сами. Просмотрите этот (и принятый ответ) мой в качестве справки. Как говорит jalf , это просто практическое правило - ожидать, что он будет оптимизирован (и, вероятно, это правильно для типов POD) , но вам нужно будет сделать резервную копию с профилированием.
По личному соглашению в программах на 'C' мне нравится помещать объявления переменных вверху функции, вверху файла или в общем файле .h. Если я начну прятать объявления в коде, это может сбить с толку и легко потерять отслеживание области видимости переменной, что приведет к нежелательным последствиям.
Для встроенных типов, таких как char *
в вашем примере, особой разницы нет. Вторая форма используется после выхода из цикла и оценивает инициализатор только один раз. Но, как говорит Джон, большинство компиляторов все равно предварительно рассчитают инициализацию.
Существует очевидная разница, если ptr
переназначается внутри цикла (и если вы не переназначаете его, вы должны сделать его char * const ptr
), в том смысле, что значение будет сохранено с предыдущей итерации вместо сброса.
Наконец, конструктор и деструктор типов, отличных от POD, будут запускаться для каждой итерации цикла.
Способ транслирования кода в действительности зависит от вашего компилятора и выполняемых им оптимизаций. Компилятор может выполнить «тупой» перевод и выделить каждый цикл, или он может разместить выделение вне цикла для вас на этапе оптимизации. На всякий случай я бы поместил объявление вне цикла. Как и все, вы можете протестировать оба и посмотреть, сколько времени занимает каждый цикл, чтобы увидеть, есть ли разница.
Я отношусь к той школе, которая считает, что лучше максимально ограничить область применения имен переменных; если ptr
не предназначен для ссылок вне цикла, то его не следует объявлять вне цикла.
Однако если something
оказывается дорогой операцией И она инвариантна (т.е. не зависит от i
) И она мешает вашему коду выполнить жесткое требование производительности, то да, вам следует вынести объявление за пределы цикла.
Это невыразимо уродливо, но вы можете сделать что-то вроде этого:
do
{
char *ptr = something;
for (int i = 0; i < 1000; i++)
{
/* use ptr here */
}
} while (0);
Вы по-прежнему ограничиваете область видимости ptr
, но больше не присваиваете его на каждой итерации цикла.