2009-07-02 2 views
24

Можно создать дубликат:
Is there a performance difference between i++ and ++i in C++?Приращение итераторов: ++ это более эффективно, чем это ++?

Я пишу программу, где итератор используется в цикле через станд :: вектор. Кто-то сказал мне, что выполнение ++ этого в инструкции for приводит к более эффективному коду. Другими словами, они говорят, что:

for (vector<string>::iterator it=my_vector.begin(); it != my_vector.end(); ++it) 

работает быстрее, чем

for (vector<string>::iterator it=my_vector.begin(); it != my_vector.end(); it++) 

ли это? Если да, то в чем причина повышения эффективности? Все это ++/++ это переносит итератор на следующий элемент в векторе, не так ли?

+7

См. Http://stackoverflow.com/questions/24901/ – Shog9

+2

Точная копия, но гонка репа все равно. – macbirdie

+1

Речь идет об итераторах, и так должны ответы. Другие вопросы, похоже, спрашивают об общей разнице. Я думаю, что они связаны с вопросами, но не точными дубликатами? –

ответ

2

Иногда да. С некоторыми это будет оптимизировано и будет одинаковым. Для std :: vector <> (и других std-итераторов) он, скорее всего, будет оптимизирован для того, чтобы быть одинаковым.

0

Да. Насколько я помню, ++ он эффективнее, чем ++, потому что он ++ создает временный объект, а ++ - нет.

1

Да ++ это более эффективно, потому что он ++ должен возвращать копию объекта, а затем увеличивать его.

31

Причина, по которой ускорение заключается в том, что пост-инкремент должен сделать копию старого значения для возврата. Как сказал GotW #2, «Preincrement более эффективен, чем postincrement, потому что для postincrement объект должен увеличиваться, а затем возвращать временное, содержащее его старое значение. Обратите внимание, что это верно даже для встроенных функций, таких как int».

GotW #55 обеспечивает канонический вид postincrement, который показывает, что он должен делать прединкремента плюс немного больше работы:

T T::operator++(int) 
{ 
    T old(*this); // remember our original value 
    ++*this;  // always implement postincrement 
        // in terms of preincrement 
    return old;  // return our original value 
} 

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

+2

Обратите внимание, что достойные компиляторы оптимизируют копию старого значения, если он никогда не будет использоваться. – Novelocrat

+2

Точно: вы не можете обещать, что преинкремент более эффективен, чем постинкремент, потому что (а) стандарт его не требует, и (б) довольно легко изобретать комбинации исходного кода и компилятора, где они одинаково эффективны. –

+0

Но вы можете предположить, что преинкремент не менее эффективен, чем постинкремент. Так почему бы просто не использовать его всегда, если они эквивалентны? –

2

Существует вероятность того, что он ++ создаст временную копию.

Кроме того, на C++ существует вероятность того, что кто-то перегрузил оператора постинкретаря.

Обе эти вещи могут снизить производительность и преинкремент. На практике это тоже не имеет большого значения. В частности, временная копия будет оптимизирована большинством компиляторов, поскольку в третьем выражении цикла For нет побочных эффектов.

6

Это вряд ли имеет значение для вектора.

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

Векторные итераторы, вероятно, являются «просто указателями» (в оптимизированных, не-отладочных сборках), и как operator++ s будут встроены. Поскольку возвращаемое значение не используется, копия обычно будет удалена. Так что это не будет иметь никакого значения. Я имею обыкновение печатать ++it, потому что:

1) В какой-то день это может иметь значение для некоторого типа итератора, и я не хочу делать что-то особенное для этого типа.

2) Лично я считаю, что префиксный оператор более четко выражает намерение: «увеличивайте его», а не «используйте его, а затем увеличивайте».

+0

Я бы сказал, что номер 2 для меня был более запутанным, чтобы увидеть ++, чем это ++. Например, глядя на регулярный int for loop, for (int i = 0; i <10; i ++) говорит мне, что у меня есть целое i, которое я установил в 0 (по назначению, потому что я хочу его 0 в первый раз), I хочу сделать это, пока i меньше 10, и я хочу увеличивать i каждый раз после каждого цикла). поэтому, чтобы увидеть ++, это было очень запутанно для меня в первый раз, я помню, что думал (почему бы вам не хотеть повторять перед чем-то?) Почему бы вам просто не настроить его на то, что вы хотите, а не на 1 меньше, чем хотите?). Я получаю это сейчас, но все же – Josh

+0

@Josh: хорошо, но это только следствие полной неуверенности новичка относительно того, когда выполняется последняя часть цикла for. Конечно, вы все еще инициализируетесь до 0, и он все еще имеет значение 0 в первый раз через цикл, 1 во второй раз и т. Д., Независимо от того, пишете ли вы '++ i' или' i ++ '. Честно говоря, если запись '++ i' приглашает новичка разрешить эту путаницу раньше, чем позже, и поймите, что предложение выполняется после * тела цикла, независимо от того, что в нем, то я бы оценил его как дополнительное преимущество для '++ i'! –

+0

Наверное, я должен помешать воспитывать нехороших учителей в старшей школе, прежде чем отправиться в колледж. Они сказали нам, что я имел в виду, что он увеличивал бы до оценки того, что внутри цикла, и i ++ будет увеличиваться после оценки того, что находится внутри цикла. Если бы с самого начала мне было сказано правильно, путаница никогда не существовала бы. – Josh

2

он ++ выполняет следующие операции:

  1. создать копию из него
  2. приращение его
  3. возврат оригинала (не увеличивается) он

++ она выполняет следующие операции:

  1. прирост это
  2. возвращение его

Поскольку ++ создает копию, можно сказать, что «медленнее». Однако любой достойный компилятор оптимизирует эту разницу для большинства определенных типов. Для некоторых пользовательских типов это может быть быстрее.

+0

Возможно, вы имели в виду "slower"? – Gobe