Разница в производительности между итератором ++ и итератором ++?
Мой помощник утверждает, что для типов объектов preincrement более эффективен, чем post increment
например.
std::vector<std::string> vec;
... insert a whole bunch of strings into vec ...
// iterate over and do stuff with vec. Is this more efficient than the next
// loop?
std::vector<std::string>::iterator it;
for (it = vec.begin(); it != vec.end(); ++it){
}
// iterate over and do stuff with vec. Is this less efficient than the previous loop?
std::vector<std::string>::iterator it;
for (it = vec.begin(); it != vec.end(); it++){
}
Ответы
Ответ 1
Postincrement должен возвращать значение, которое итератор имел до того, как он увеличивался; так что предыдущее значение нужно скопировать где-нибудь, прежде чем изменять его с помощью соответствующего приращения, чтобы он был доступен для возврата. Дополнительная работа может быть немного или много, но она, конечно, не может быть меньше нуля, по сравнению с преинкрементом, которая может просто выполнить приращение, а затем вернуть только что измененное значение - без копирования//сохранения//и т.д.
Итак, если вы специально НЕ ДОЛЖНЫ иметь постинкремент (потому что вы каким-то образом используете значение до инкремента), вы всегда должны использовать preincrement.
Ответ 2
Операторы приращения по умолчанию будут выглядеть так:
class X
{
X operator++(int) // Post increment
{
X tmp(*this);
this->operator++(); // Call pre-increment on this.
return tmp;
}
X& operator++() // Pre increment
{
// Do operation for increment.
return *this;
}
};
Обратите внимание, что пост-инкремент определяется в терминах предварительного приращения. Таким образом, Post-increment выполняет ту же работу плюс дополнительные. Обычно это конструирует копию, а затем возвращает копию через копию (обратите внимание, что Pre-increment может возвращать себя по ссылке, но Post-increment не может).
Ответ 3
Для примитивных типов я использовал это. Это помогло мне получить 10% -ное повышение во многих программах на Visual Studio еще в 1998-1999 годах. Вскоре после этого они исправили свой оптимизатор. Оператор post increment создал переменную в стеке, скопировал значение, увеличил исходный код и затем удалил переменную из стека. Как только оптимизаторы обнаружили, что он не использовался, пособие ушло.
Большинство людей не прекращали кодирование таким образом.:) Мне понадобилось несколько лет.
Для объектов я не уверен, как это будет работать. Я предполагаю, что оператор копирования будет необходим для реальной реализации пост-приращения. Он должен был бы сделать копию и использовать копию для операций и увеличить источник.
Jacob
Ответ 4
Я читал, что это не имеет никакого отношения к компиляторам, у которых есть приличный оптимизатор. Поскольку общая логика цикла одинакова для обоих, имеет смысл использовать предварительный прирост в качестве хорошей привычки программирования. Таким образом, если программист встречает "субоптимальный" компилятор, лучший результат гарантирован.
Ответ 5
Серьезно, если у вас нет проблем с производительностью из-за вызова пост-инкремента вместо предварительного приращения РАЗЛИЧИЕ РАЗЛИЧИЯ БУДЕТ ТОЛЬКО В ОЧЕНЬ РЕДКИХ ОБСТОЯТЕЛЬСТВАХ.
Обновление
Например, если ваше программное обеспечение является климатическим симулятором, а operator++
заставляет симуляцию двигаться вперед (т.е. ++simulation
дает вам следующий шаг в симуляции, а simulation++
делает копию текущий шаг в моделировании, продвигает симуляцию, а затем передает вам копию), тогда производительность будет проблемой.
Более реалистично, в комментарии, первоначальный вопросник упоминает, что мы обсуждаем встроенный проект с (по-видимому) требованиями к реальному времени. В этом случае вам нужно действительно посмотреть на вашу конкретную реализацию. Я серьезно сомневаюсь, что у вас будут заметные замедления, повторяющиеся с помощью std::vector
с пост-инкрементом вместо предварительного приращения, хотя я не сравнивал какую-либо реализацию STL по этому вопросу.
Не выбирайте один из них по соображениям производительности. Выберите один за другим для ясности/обслуживания. Лично я по умолчанию пре-инкремент, потому что мне вообще не наплевать, какое значение было до приращения.
Если ваш мозг взрывается, когда вы видите ++i
вместо i++
, возможно, пора подумать о том, чтобы перейти в другую линию работы.
Ответ 6
посмотрите на http://discuss.fogcreek.com/joelonsoftware/default.asp?cmd=show&ixPost=171881
Ответ 7
Я знаю, что это похоже на "ангар" в авиации. Я уверен, что это чисто академический, и вы знаете, что он делает разницу в разнице, вам нужно переосмыслить свой код.
Пример. Я получил комментарий к некоторым ответам, которые я дал на вопрос о настройке производительности, и он выглядел следующим образом:
Лицо: Я попробовал ваш метод случайного прекращения и посмотрел на стек вызовов. Я делал это несколько раз, но это не имеет смысла. Все время он глубоко в коде кода итератора. Что хорошего в этом?
Я: Это здорово! Это означает, что почти все ваше время идет на увеличение итераторов. Посмотрите выше стека и посмотрите, откуда он. Замените это простым приращением целых чисел, и вы получите огромное ускорение.
Конечно, вы можете предпочесть привлекательность итератора-приращения, но достаточно легко узнать, стоит ли вам стоить вам высокой производительности.