2.8 インクリメントとデクリメント
2.8.1 変数の値を 1 増やす
プログラムで何らかの回数を数えるときなど、しばしば変数の現在の値を 1 増やすか、または 1 減らすという処理が行われます。変数の値を 1 増やすという処理のことをインクリメント(increment)と呼び、1 減らす処理のことをデクリメント(decrement)と呼びます。
整数型の変数 i が宣言されているものとして i = i + 1 または i += 1 と書くことで、現在の値に 1 を加えられますが、インクリメント演算子(increment operators)を使うことで、より簡単に同じ演算を行えます。同様に、変数の値を 1 減らす処理にはデクリメント演算子(decrement operators)が用いられます。
インクリメント演算子は + 記号を 2 つ繋げた ++ で表され、デクリメント演算子は - 記号を 2 つ繋げた -- で表されます。これらの演算子は単項演算子であり、インクリメントまたはデクリメントする変数を項として受け取ります。
これまで紹介した単項演算子(単項 - 演算子や ! 演算子など)は右に項を指定しましたが、インクリメント及びデクリメント演算子は左右のどちらか一方に項を指定できます。整数型の変数 i が宣言されているものと仮定したとき
++i --i
と書くこともできますし
i++ i--
と書くこともできます。
前者のインクリメント演算子 ++i 及びデクリメント演算子 --i は、項よりも前に演算子が置かれることから前置インクリメント演算子(prefix increment operator)及び前置デクリメント演算子(prefix decrement operator)と呼ばれます。
後者のインクリメント演算子 i++ 及びデクリメント演算子 i-- は、項よりも後に演算子が置かれることから後置インクリメント演算子(postfix increment operator)及び後置デクリメント演算子(postfix decrement operator)と呼んで前置と区別します。
前置と後置のどちらを使っても、変数の値を 1 増やすまたは減らすという結果は同じです。特別な意図がある場合を除き、多くは後置が使われる傾向にあります。
#include <iostream> int main() { int i = 10; i++; std::cout << "i = " << i << "\n"; i--; std::cout << "i = " << i << "\n"; return 0; }
コード1は、後置インクリメント演算子と後置デクリメント演算子を使って int 型の変数 i の値を変更しています。i 変数は 10 で初期化されていますが、インクリメント後に出力した結果は 1 増えて 11 になり、デクリメント後に出力した結果は 1 減って 10 に戻っていることが確認できます。
コード1の結果は、前置インクリメント演算子と前置デクリメント演算子を使った場合でも同じです。
#include <iostream> int main () { int i = 10; ++i; std::cout << "i = " << i << "\n"; --i; std::cout << "i = " << i << "\n"; return 0; }
コード2はコード1のインクリメント演算子とデクリメント演算子を前置に置き換えたものです。実行結果は同じであることが確認できます。
ただし、前置と後置は完全に同じものではありません。変数をインクリメント及びデクリメントするという結果は同じですが、返される値が異なります。加算演算子のよる 1 + 2 という式が 3 という結果を返すように 、インクリメント演算子やデクリメント演算子にも式の結果が存在します。例えば
int i = 10, k; k = i++;
という式の結果、k 変数にはインクリメント演算子の結果が代入されます。では k 変数にはどのような値が代入されるのでしょうか。この k に入る値が、前置と後置で異なるのです。
前置の場合はインクリメントまたはデクリメントした後の値が格納されるのに対し、後置の場合は前の変数の値が返されます。従って k = i++ の結果 k 変数に代入される値は 10 ですが、k = ++i と書いた場合は 11 が代入されることになります。前置の場合はインクリメント後、後置の場合はインクリメント前の値が代入されることになります。
#include <iostream> int main() { int x = 10, y = 10; std::cout << "x++ = " << x++ << "\n"; std::cout << "x-- = " << x-- << "\n"; std::cout << "x = " << x << "\n"; std::cout << "++y = " << ++y << "\n"; std::cout << "--y = " << --y << "\n"; std::cout << "y = " << y << "\n"; return 0; }
コード3は同じ値 10 で初期化されている変数 x と y に対して、インクリメント演算とデクリメント演算を行い、その結果を出力しています。x 変数に対しては後置、y 変数に対しては前置で、インクリメントとデクリメント演算を行っています。どちらも、最終的な結果は同じ 10 になりますが、過程の出力が違っていることに注目してください。このように、インクリメント演算やデクリメント演算の結果を他の式の項として利用する場合は前置と後置の違いに注意しなければなりません。
インクリメントの結果を受け取らず、単に変数の値を 1 増やすだけであれば前置でも後置でも同じ結果です。しかし、後置の場合はインクリメントする前の値が結果として返されるため、内部的にはインクリメント前の値を一時的に保持する必要があり、これがパフォーマンスを低下させる可能性が指摘されています。この差が致命的な問題を発生させる可能性は低いと考えられますが、ゲームなどパフォーマンスを徹底的に追及しなければいけない分野においては、基本は前置で書く習慣がみられます。
なお、インクリメント演算子とデクリメント演算子が存在するため、+ または - 記号が連続する 2 項演算子と単項演算子の組み合わせには注意してください。例えば、減算演算子と単項 - 演算子の組み合わせはスペースで区切らなければなりません。x + (-y) という計算を x+-y と書くことは許されますが x - (-y) を x--y と書くことはできません。-- がデクリメント演算子と解釈されてしまうからです。
また i+++i のようなコードは文法上問題ありませんが (i++ ) + i なのか i + (++i) なのか混乱してしまうので避けるべきです。ちなみに、i++++i や i+++++i はコンパイルエラーになりますが i+++ +i や i+++ ++i はコンパイル可能です。実際に試して、なぜなのか考えてみてください。