Зачем использовать ++ я вместо я ++ в случаях, когда значение не используется нигде в инструкции?
Мне хорошо известно, что в С++
int someValue = i++;
array[i++] = otherValue;
имеет различный эффект по сравнению с
int someValue = ++i;
array[++i] = otherValue;
но каждый раз я вижу инструкции с приращением префикса для for-loops или просто по своему усмотрению:
for( int i = 0; i < count; ++i ) {
//do stuff
}
или
for( int i = 0; i < count; ) {
//do some stuff;
if( condition ) {
++i;
} else {
i += 4;
}
}
В последних двух случаях ++i
выглядит как попытка создать смарт-код. Я что-то наблюдаю? Есть ли причина использовать ++i
вместо i++
в последних двух случаях?
Ответы
Ответ 1
Если мы игнорируем силу привычки, "++ i" является более простой операцией концептуально: она просто добавляет ее к значению i, а затем использует ее.
i++
, с другой стороны, это "взять исходное значение i
, сохранить его как временное, добавить его в i
, а затем вернуть временное". Это требует от нас сохранения старой ценности даже после обновления i
.
И, как показал Конрад Рудольф, для использования i++
с пользовательскими типами могут быть затраты на производительность.
Итак, вопрос в том, почему не всегда просто по умолчанию ++i
?
Если у вас нет причин использовать `i ++ ', зачем это делать? Почему вы по умолчанию выполняете операцию, которая сложнее рассуждать и может выполняться медленнее?
Ответ 2
Посмотрите на возможные реализации двух операторов в собственном коде:
// Pre-increment
T*& operator ++() {
// Perform increment operation.
return *this;
}
// Post-increment
T operator ++(int) {
T copy = *this;
++*this;
return copy;
}
Оператор postfix вызывает оператор префикса для выполнения своей собственной операции: по дизайну и в принципе префиксная версия всегда будет быстрее, чем постфиксная версия, хотя компилятор может оптимизировать это во многих случаях ( и особенно для встроенных типов).
Поэтому предпочтение оператора префикса естественно; это другое, что нуждается в объяснении: почему так много людей заинтригованы использованием префиксного оператора в ситуациях, когда это не имеет значения, но никто не удивляется использованию постфиксного оператора.
Ответ 3
Как вы отметили - это не имеет значения для результата.
Существует оценка производительности для не-примитивных типов.
Также семантически использование pre-increment обычно становится более ясным, если вы показываете намерение теста, когда используется возвращаемое значение, поэтому лучше использовать его обычно, чем post-increment, чтобы избежать случайного тестирования старого значения.
Ответ 4
Есть одна причина, и это связано с перегруженными операторами. В перегруженной функции postincrement функция должна помнить предыдущее значение объекта, увеличивать его, а затем возвращать предыдущее значение. В функции preincrement функция может просто увеличивать объект, а затем возвращать ссылку на себя (новое значение).
В случае целого числа указанное выше, вероятно, не будет применяться, поскольку компилятор знает контекст, в котором выполняется инкремент, и будет генерировать соответствующий код приращения в любом случае.
Ответ 5
Да, по соображениям производительности. В случае пошагового приращения копия переменной я должна быть сделана до приращения, чтобы можно было вернуть старое значение (хотя вы не используете возвращаемое значение). В случае предварительного приращения эта копия не требуется.
Ответ 6
Существует мало оснований полагаться на предварительный прирост по сравнению с последующим приращением, когда вы говорите о натуральных типах, таких как целые числа. Компилятор обычно может генерировать один и тот же код в обоих случаях в любом случае, если вы не используете возвращаемое значение. Это не относится к более сложным типам, таким как итераторы.
Ответ 7
С++ FAQ Lite имеет приятное обсуждение i++
vs. ++i
здесь:
[13.15] Что более эффективно: я ++ или ++ i?
В частности, относительно того, какую форму использовать в цикле for
, часто задаваемые вопросы выражают предпочтение ++i
. Вот текст:
Итак, если вы пишете i++
как инструкцию, а не как часть более крупное выражение, почему бы просто написать ++i
вместо этого? Вы никогда не проигрываете ничего, и вы иногда что-то выигрываете. Программисты старой строки C используется для записи i++
вместо ++i
. Например, они скажут: for (i = 0; i <10; i++)
.... Так как это использует i++
как инструкцию, а не как часть более крупное выражение, то вместо этого вы можете использовать ++i
. Для симметрии, я лично защищаю этот стиль, даже если он не улучшить скорость, например, для встроенных типов и типов классов с постфиксные операторы, которые возвращают void.