for (int i = 0; i <myVector.size (); ++ i) Сколько раз вызывается size ()? - PullRequest
1 голос
/ 07 сентября 2011

Если у меня есть myVector, который является вектором STL, и выполнить цикл следующим образом:

for(int i=0;i<myVector.size();++i) { ... }

Воспроизводит ли компилятор C ++ какой-либо трюк, чтобы вызвать size() только один раз, или он будет вызван size()+1 раз?

Я немного растерялся, кто-нибудь может помочь?

Ответы [ 8 ]

5 голосов
/ 07 сентября 2011

Логически, myVector.size() будет вызываться при каждой итерации цикла - или, по крайней мере, компилятор должен генерировать код , как если бы вызывался каждый раз.

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

Так что на самом деле, вероятно, мало причин для беспокойства по поводу того, что происходит с vector::size().

Обратите внимание, что list::size() может быть другой историей - стандарт C ++ 03 допускает линейную сложность (хотяЯ думаю, что это редко, и стандарт C ++ 0x меняет list::size() требования на постоянную сложность).

3 голосов
/ 07 сентября 2011

Я предполагаю, что вектор не меняет размер в цикле.Если он меняет размер, невозможно сказать, не зная, как он меняет размер.

На абстрактной машине C ++ он будет вызываться ровно size()+1 раз.И в конкретной реализации он будет иметь наблюдаемое поведение, эквивалентное тому, что его вызывали size()+1 раз (это называется как если бы правило).

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

2 голосов
/ 07 сентября 2011

Он может быть вызван один раз, может быть вызван size+1 раз или вообще никогда не может быть вызван.Предполагая, что размер вектора не меняется, ваша программа будет вести себя , как если бы она была вызвана size+1 раз.

Здесь есть две оптимизации: во-первых, std::vector::size()вероятно, встроенный, так что его никогда не могут вообще «назвать» в традиционном смысле.Во-вторых, компилятор может определить, что он оценивает size() только один раз или, возможно, никогда:

Например, этот код может никогда не вычислять std::vector::size():

for(int i = 0; i < myVector.size(); ++i) { ; }

Любой из этих цикловможет оценить std::vector::size() только один раз:

for(int i = 0; i < myVector.size(); ++i) { std::cout << "Hello, world.\n"; }
for(int i = 0; i < myVector.size(); ++i) { sum += myVector[i]; }

Хотя этот цикл может оценивать std::vector::size() много раз:

for(int i = 0; i < myVector.size(); ++i) { ExternalFunction(&myVector); }

В конечном итоге ключевыми вопросами являются:

  • Почему вас это волнует? И
  • Откуда вы знаете?

Почему вас волнует, сколько раз вызывается size()?Вы пытаетесь заставить вашу программу работать быстрее?

Как бы вы узнали?Так как size() не имеет видимых побочных эффектов, как вы узнаете, кто его много раз вызывал (или оценивал иначе)?

2 голосов
/ 07 сентября 2011

Будет вызываться size + 1 раз. Изменение размера vector повлияет на количество итераций.

1 голос
/ 07 сентября 2011

Он будет вызываться до тех пор, пока условие не будет искажено (например, size () может меняться каждый раз).Если size() остается постоянным, то это size() + 1 раз.

Со страницы MSDN о for:

for (init-expression; cond-выражение; цикл-выражение)
оператор

cond-выражение

Перед выполнением каждой итерации оператора, включая первую итерацию.Оператор выполняется только в том случае, если выражение cond имеет значение true (ненулевое).Выражение, которое оценивается как целочисленный тип или тип класса, который имеет однозначное преобразование в целочисленный тип.Обычно используется для проверки критериев завершения цикла.

1 голос
/ 07 сентября 2011

Он будет вызываться size () + 1 раз (возможно, компилятор может распознать его как инвариант в цикле, но вы не должны на это рассчитывать)

0 голосов
/ 08 сентября 2011

На самом деле myVector.size() будет встроено, поэтому не будет никакого вызова вообще.Просто сравнивая значение регистра с местом в памяти.Конечно, я говорю о сборке релиза.

В отладочной сборке она будет вызываться size()+1 раз.

РЕДАКТИРОВАТЬ: Нет сомнений, что существует такая реализация компилятора или STL, которая не может оптимизировать myVector.size().Но шансы встретиться с ними очень малы.

0 голосов
/ 07 сентября 2011

Это будет называться размером + 1 раз, как упоминал Эрнест. Однако, если вы уверены, что размер не меняется, вы можете применить оптимизацию и сделать свой код таким:

for (unsigned int i = 0, e = myVector.size (); i < e; ++i)

... в этом случае size () будет вызываться только один раз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...