Стоит ли вычислять векторный размер для циклов, каждая итерация?

Компилятор С++ позаботится о таких случаях, как здания: 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

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

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