Урок 40. Инкремент. Декремент. Побочные эффекты

   ⁄ 

 Обновлено 5 Мар 2017

  ⁄   

Операции инкремента (увеличение на 1) и декремента (уменьшение на 1) переменной настолько используемые, что у них есть свои собственные операторы в C++. Так еще и две версии: префикс и постфикс.

Оператор Символ Пример Операция
Префиксный инкремент (пре-инкремент) ++ ++x Инкремент x, затем вычисление x
Префиксный декремент (пре-декремент) −− −−x Декремент x, затем вычисление x
Постфиксный инкремент (пост-инкремент) ++ x++ Вычисление x, затем инкремент x
Постфиксный декремент (пост-декремент) −− x−− Вычисление x, затем декремент x

Операторы инкремента/декремента версии префикс — просты. Значение переменной х сначала увеличивается или уменьшается, а затем уже вычисляется. Например:

А вот с операторами инкремента/декремента версии постфикс несколько сложнее. Компилятор создает временную копию переменной х, увеличивает или уменьшает оригинальный х (не копию), а затем вычисляет копию х. Только после этого копия удаляется.

Рассмотрим детальнее. Во-первых, компилятор создает временную копию х, которая имеет то же значение, что и оригинал (5). Затем увеличивается первоначальный х с 5 до 6. После компилятор вычисляет временную копию, значение которой — 5, и присваивает это значение переменной у. Затем копия удаляется. Следовательно, в конце, переменная у = 5, а переменная х = 6.

Вот еще один пример, показывающий разницу между этими версиями:

Результат:

5 5
6 4
6 4
6 4
7 3

В третьей строчке, х и у увеличиваются/уменьшаются на единицу непосредственно перед обработкой компилятора, так что сразу выводятся их новые значения. На пятой строчке, временные копии (х = 6, у = 4) отправляются в cout, а уже только потом оригинальные х и у увеличиваются/уменьшаются на единицу. Именно поэтому изменения значений операторов версии постфикс не видно до следующей строки.

Версия префикс увеличивает/уменьшает значения перед обработкой компилятора, версия постфикс — после.

Правило: Используйте префиксный инкремент и префиксный декремент, вместо постфиксного инкремента и постфиксного декремента. Версии префикс не только более производительны, но и вероятность возникновения ошибок и проблем с ними намного меньше.  

Побочные эффекты

Функция или выражение имеет побочный эффект (side effect), если она/оно изменяет состояние чего-либо, делает ввод/вывод или вызывает другие функции, которые имеют побочные эффекты.

В большинстве случаев, они полезны:

В примере выше, оператор присваивания имеет побочный эффект, который проявляется в изменении значения х. Даже после окончания выполнения кода значением переменной х будет число 5. Оператор ++ имеет побочный эффект инкремента переменной х. Вывод х имеет побочный эффект внесения изменений в консольное окно.

Также, side effects могут приводить и к неожиданным результатам:

C++ не определяет порядок, в котором вычисляются аргументы функции. Если левый аргумент будет вычисляться первым, то add(5, 6), а результат — 11. Если правый аргумент будет вычисляться первым, то add(6, 6), а результат — 12! А проблема кроется то только в побочном эффекте одного из аргументов функции add().

Вот еще пример:

Каков результат этой программы? Ответ: не определено. Если инкремент х выполнится до присваивания, то ответ — 1. Если же после, то ответ — 2.

Есть и другие случаи, в которых C++ не определяет порядок обработки данных, поэтому в разных компиляторах могут быть разные результаты. Но даже в тех случаях, когда C++ и уточняет порядок обработки, то некоторые компиляторы все равно вычисляют переменные с побочными эффектами некорректно. Этого всего можно избежать, если использовать переменные с side effects не больше одного раза в одном стейтменте.

Правило: Не используйте переменную с побочным эффектом больше одного раза в одном стейтменте. Если вы это сделаете, то результат будет не определен.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (13 оценок, среднее: 4,92 из 5)
Загрузка...
Поделиться в:
Подписаться на обновления:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *