Вопрос по c++, stl – Увеличивающиеся итераторы: ++ эффективнее, чем ++? [Дубликат]

25

Possible Duplicate:
Is there a performance difference between i++ and ++i in C++?

Я пишу программу, в которой итератор используется для цикла по std :: vector. Кто-то сказал мне, что выполнение ++ в выражении 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++ )

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

Увидеть:stackoverflow.com/questions/24901 Shog9♦
Это касается итераторов, и ответы должны быть такими же. Другие вопросы, кажется, задают об общей разнице. Я думаю, что это связанные вопросы, но не точные дубликаты? Johannes Schaub - litb
Тем не менее, я согласен с вами, похоже, что нет разницы, когда он только спрашивает об эффективности. Похоже на дурака! :) Johannes Schaub - litb
Точная копия, но реп-гонка в любом случае. macbirdie
@litb: сложный вызов ... Другой вопрос касается специфических для C ++ различий в производительности между двумя операторами, и ответы отражают это при обсуждении того, как реализация объекта может потенциально привести к таким несоответствиям. Итераторы являются (или могут быть) объектами; так что это действительно подмножество предыдущего вопроса. Shog9♦

Ваш Ответ

7   ответов
2

потому что ему ++ нужно вернуть копию объекта, а затем увеличить саму себя.

8

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

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

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

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

Я полагаю, что я должен записаться до плохих учителей в старшей школе, прежде чем я уйду в колледж. Они сказали нам ++, я имел в виду, что он будет увеличиваться до оценки того, что находится внутри цикла, а i ++ будет увеличиваться после оценки того, что внутри цикла. Если бы мне сказали правильно с самого начала, путаницы никогда бы не было.
@Josh: хорошо, но это всего лишь следствие полной путаницы новичка в отношении того, когда выполняется последняя часть цикла for. Конечно, вы по-прежнему инициализируете в 0, и он по-прежнему имеет значение 0 в первый раз в цикле, 1 во второй раз и т. Д., Независимо от того, пишете ли вы++i или жеi++, Честно говоря, если писать++i предлагает новичку скорее разрешить эту путаницу, а не позже, и понять, что предложение выполненоafter тело цикла независимо от того, что в нем находится, тогда я буду оценивать его как дополнительное преимущество для++i!
Я должен сказать, что номер 2 для меня было более запутанным, чтобы увидеть ++ это, чем это ++. Например, глядя на обычный цикл int for, for (int i = 0; i & lt; 10; i ++) говорит мне, что у меня есть целое число i, которое я установил в 0 (специально, потому что я хочу, чтобы оно было 0 в первый раз), Я хочу сделать это до тех пор, пока я меньше 10, и я хочу увеличивать i на ОДИН каждый раз после завершения цикла). чтобы увидеть ++, это было очень странно для меня в первый раз, я помню, как подумал (почему вы хотите повторять ПЕРЕД выполнением чего-либо? почему бы вам просто не установить то, что вы хотите, а не на 1 меньше, чем то, что вы хотите? ). Я понял это сейчас, но все еще
0

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

2

Также в C ++ есть вероятность, что кто-то перегружен оператором постинкремента.

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

5

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

create a copy of it increment it return the original (non-incremented) it

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

increment it return it

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

Вы имели в виду "медленнее"?
2

std :: vector & lt; & gt; (и другие std-итераторы) он, скорее всего, будет оптимизирован, чтобы быть таким же.

33

по которой преинкремент быстрее, заключается в том, что постинкремент должен сделать копию старого значения для возврата. КакПОЛУЧИЛО № 2 иными словами, «Преинкремент более эффективен, чем постинкремент, потому что для постинкремента объект должен сам себя увеличивать, а затем возвращать временное значение, содержащее его старое значение. Обратите внимание, что это верно даже для встроенных функций, таких как int. & Quot;

ПОЛУЧИЛО № 55 предоставляет каноническую форму постинкремента, которая показывает, что он должен выполнять преинкремент плюс еще немного работы:

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 ++.

Обратите внимание, что приличные компиляторы будут оптимизировать копию старого значения, если оно никогда не будет использовано.
Но вы можете предположить, что прединкремент по крайней мере так же эффективен, как постинкремент. Так почему бы просто не использовать его всегда, когда они в противном случае эквивалентны?
Точно: вы не можете обещать, что предварительное добавление более эффективно, чем постинкрементное, потому что (а) стандарт не требует этого и (б) довольно легко изобрести комбинации исходного кода и компилятора, где оба одинаково эффективны.
Согласовано: я думаю, что используйте preincrement, где это возможно, поскольку я не могу придумать законную причину, по которой он будет хуже, чем post. Если какой-то класс перегружает оба оператора (плохо) и каким-то образом ухудшает предварительный инкремент, то вызывающего абонента нельзя обвинить в том, что он не обошел его. Я просто не думаю, что нужно обещать, что он "более эффективен" (который многие будут читать как «строго более эффективный»), когда такой гарантии нет, и, как правило, они идентичны в оптимизированном коде.

Похожие вопросы