Стоит ли вычислять векторный размер для циклов, каждая итерация?
Компилятор С++ позаботится о таких случаях, как здания: vector:
for (int i = 0; i < buildings.size(); i++) {}
то есть он замечает, что здания изменены в цикле или нет, а затем
основанный на том, что не оценивать его на каждой итерации? Или, может быть, я должен сделать это сам,
не так красиво, но:
int n = buildings.size();
for (int i = 0; i < n; i++) {}
Ответы
Ответ 1
buildings.size()
, скорее всего, будет встроен компилятором для прямого доступа к полю частного размера в классе vector<T>
. Поэтому вы не должны отделять вызов от size
. Такая микро-оптимизация - это то, о чем вы вообще не хотите беспокоиться (если вы не находитесь в каком-то очень узком цикле, идентифицированном как узкое место при профилировании).
Ответ 2
Не решайте, идти ли за то или другое, думая о производительности; ваш компилятор может или не может встроить вызов - и std::vector::size()
также имеет постоянную сложность.
То, что вы должны действительно рассмотреть, это правильность, потому что две версии будут вести себя по-другому, если вы добавите или удалите элементы во время итерации.
Если вы не изменяете вектор каким-либо образом в цикле, придерживайтесь прежней версии, чтобы избежать небольшого состояния (переменная n
).
Ответ 3
Если компилятор может определить, что buildings
не мутируется в цикле (например, если он представляет собой простой цикл без вызовов функций, которые могут иметь побочные эффекты), он, вероятно, отключит вычисление. Но вычисление размера вектора в любом случае является одним вычитанием, которое также должно быть довольно дешевым.
Запишите код очевидным образом (size
внутри цикла), и только если профилирование показывает вам, что он слишком медленный, если вы рассматриваете альтернативный механизм.
Ответ 4
Я пишу петли следующим образом:
for (int i = 0, maxI = buildings.size(); i < maxI; ++i)
Принимает во внимание сразу несколько проблем: предположим, что max фиксирован спереди, больше не думает о потерянной производительности, консолидирует типы. Если оценка находится в среднем выражении, это предполагает, что цикл изменяет размер коллекции.
Слишком плохой язык не позволяет разумного использования const, иначе он будет const maxI.
OTOH для все большего числа случаев я скорее использую какой-то алгоритм, лямбда даже позволяет сделать его похожим на традиционный код.
Ответ 5
Предполагая, что функция size()
является встроенной функцией для базового шаблона, можно также предположить, что это очень мало накладных расходов. Он сильно отличается от, скажем, strlen()
в C, что может иметь значительные накладные расходы.
Возможно, еще быстрее использовать int n = buildings.size();
- потому что компилятор может видеть, что n
не меняется внутри цикла, поэтому загружайте его в регистр и не косвенно выбирайте размер вектора. Но это очень маргинально, и только очень жесткие, оптимизированные петли нуждаются в этом лечении (и только после анализа и определения его выгоды), поскольку он НЕ ВСЕГДА работает так, как вы ожидаете в этом отношении.
Ответ 6
Только начинайте вручную оптимизировать такие вещи, если это действительно проблема производительности. Затем измерьте разницу. В противном случае у вас будет много недостижимого уродливого кода, который сложнее отлаживать и менее продуктивно работать. Большинство ведущих компиляторов, вероятно, оптимизируют его, если размер не изменится в цикле.
Но даже если он не будет оптимизирован, тогда он, вероятно, будет встроен (поскольку шаблоны встроены по умолчанию) и почти ничего не стоят.