🔄️

前置と後置を少し掘り下げる

に公開

C++ の名前って「C の後継」ということで「C/C++ のインクリメント演算子で 1 を足している」という賢い名前になっていますが、実はインクリメント演算子には前置と後置という2つのタイプがあります。

int x;
++x; // 前置インクリメント
x++; // 後置インクリメント

デクリメント演算子も同じく2つあります。

--x; // 前置デクリメント
x--; // 後置デクリメント

上記の使い方だと、動作は結果的に変わらないです。でもその変数をその場で使いたい場合は、以下のように違ってきます。

  • 前置インクリメント(および前置デクリメント演算子)は、変数の値に 1 を足し(または引き)、その結果を返します。
  • 後置インクリメント(および後置デクリメント演算子)は、変数の値に 1 を足し(または引き)、その前の値を返します。

前置の方が 1 が足された(または引かれた)結果を返すため、詳しくない人でも予想する挙動だと思います。
それに対して、後置の方は前の値を返すため、少し予想外かもしれないです。
後、正直その前の値を使うユースケースが思いつかないです。ググったみたら、以下のようなコードが出てきました。

int i = 0;
while (i <= 5) {
    printf("%d ", i++);
}

確かにここは後置の方を使った方がコードが短くなりますが、詳しくない人は 1 から出力されると思ってしまうかもしれないため、あんまりお勧めできないです。
後置インクリメントはやはり以下のように使った方が一番分かりやすいです。

int i = 0;
while (i <= 5) {
    printf("%d ", i);
    i++;
}

では、変数をその場で使わない時はどちらを使いますか?

インクリメント/デクリメント演算子を一番見かけるのはやはり for ループです。上記の while ループを for ループに書き換えると以下になります。

for (int i = 0; i <= 5; i++)
{
    printf("%d ", i);
}

for ループは大体後置の方が使われているイメージがありますが、たまに以下のように前置の方が使われています。

for (int i = 0; i <= 5; ++i)
{
    printf("%d ", i);
}

因みに、私もこういう場合は前置の方を使います。理由を知るために、両方の実装例を見てみましょう。もちろんコンパイラによっては実装が違っていて、実際の実装はもっと複雑です。

// 前置インクリメント
T& operator++(T& a)
{
    a += 1;
    return a;
}
// 後置インクリメント
// 2個目のint型の引数は後置演算子と分かるためにあるだけで、
// 値はいつも 0 なので、無視でいいです。
T operator++(T& a, int)
{
    T temp = a;
    a += 1;
    return temp;
}

前置の方は 1 を足して、その変数自体を参照で返すだけで簡単です。
後置の方も 1 を足すのですが、その前の値を覚えておくためにコピーを作ります。
そもそも戻り値を使わない場合は、コピーを作らない前置の方を使った方がいいのではということで、いつも前置の方を使っています。
コンパイラがどうせオプティマイズしてくれるため、実際はどちらでもいいとは思いますが、どちらでもいいのだったら、前置の方を使おうと思っているだけです。

なので、これからC++ではなく、++Cを使いましょう!(違


|cpp記事一覧へのリンク|

Discussion