web-dev-qa-db-ja.com

forループの++ iまたはi ++ ??

可能性のある複製:
C++でi ++と++ iのパフォーマンスに違いはありますか?

一部のプログラマが++iを書く代わりに、通常のforループでi++を書く理由はありますか?

53
Ismail Marmoush

整数の場合、プリインクリメントとポストインクリメントに違いはありません。

iが非自明なクラスのオブジェクトである場合、++iが一般的に推奨されます。これは、オブジェクトが変更されてから評価されるのに対し、i++は評価後に変更されるため、コピーが必要です作られる。

81

++iは、そのセマンティクスによりわずかに効率的です。

++i;  // Fetch i, increment it, and return it
i++;  // Fetch i, copy it, increment i, return copy

Intのようなインデックスの場合、効率の向上は最小限です(ある場合)。イテレータや他の重いオブジェクトの場合、そのコピーを避けることは本当の勝利になります(特にループ本体に多くの作業が含まれていない場合)。

例として、任意の精度の整数を提供する理論的なBigIntegerクラスを使用した次のループを考えてみてください(したがって、ある種のベクトルのような内部)。

std::vector<BigInteger> vec;
for (BigInteger i = 0; i < 99999999L; i++) {
  vec.Push_back(i);
}

そのi ++操作には、インデックスオブジェクトのコピーを本質的にもう1つ作成するだけのループのコピー構築(つまり、演算子の新しい、桁ごとのコピー)と破棄(演算子の削除)が含まれます。基本的に、プレフィックスで十分な場合にpostfix incrementを使用するだけで、実行する作業を2倍にした(そしてメモリの断片化を増加させる可能性が高い)。

102
Drew Hall

++iは事前インクリメントです。 i++はポストインクリメントです。
ポストインクリメントのマイナス面は、追加の値が生成されることです。 iの変更中に古い値のコピーを返します。したがって、可能な場合は避けてください。

7
Richard

整数では、それが好みです。

ループ変数がクラス/オブジェクトである場合、違いが生じる可能性があります(プロファイルが重要な違いがあるかどうかは、プロファイリングのみで確認できます)。ポストインクリメントバージョンでは、破棄されるオブジェクトのコピーを作成する必要があるためです。

そのコピーの作成が高価な操作である場合は、ループを通過するたびにその費用を支払うことになります。理由はまったくありません。

Forループで常に++iを使用する習慣になった場合、この特定の状況で何をしているのが理にかなっているかを考える必要はありません。あなたはいつもいつもです。

4
bgporter

これには理由があります:パフォーマンス。 i ++はコピーを生成します。これをすぐに破棄すると無駄になります。確かに、コンパイラはiがプリミティブの場合、このコピーを最適化できますが、そうでない場合はできません。 this questionを参照してください。

2
wilhelmtell

Saltで自重の価値があるコンパイラは、

for(int i=0; i<10; i++)

そして

for(int i=0;i<10;++i)

++ iおよびi ++には同じコストがあります。唯一異なるのは、++ iの戻り値がi + 1であるのに対し、i ++の戻り値はiであるということです。

したがって、++ iを好む人にとっては、おそらく正当な正当化はなく、個人的な好みがあります。

編集:他のすべての投稿で述べたように、これはクラスにとって間違っています。 i ++は、iがクラスの場合にコピーを生成します。

1
rtpg

他の人がすでに指摘したように、ユーザー定義型の場合、事前インクリメントは通常、事後インクリメントよりも高速です。これがなぜそうなのかを理解するには、典型的なコードパターンを見て、両方の演算子を実装します。

_Foo& operator++()
{
    some_member.increase();
    return *this;
}

Foo operator++(int dummy_parameter_indicating_postfix)
{
    Foo copy(*this);
    ++(*this);
    return copy;
}
_

ご覧のとおり、プレフィックスバージョンはオブジェクトを単に変更し、参照によってそれを返します。

一方、後置バージョンは、実際のインクリメントが実行される前にコピーを作成する必要があり、そのコピーは値によって呼び出し元にコピーされます。ソースコードから明らかなように、後置バージョンは接頭辞バージョンへの呼び出しを含むため、より多くの作業を行う必要があります:++(*this);

組み込み型の場合、値を破棄する限り、つまり_++i_などのより大きな式に_i++_または_a = ++i_を埋め込まない限り、違いはありません。または_b = i++_。

1
fredoverflow

個人の好み。

通常。時々それは重要ですが、ここではジャークのように見えませんが、尋ねなければならない場合はおそらくそうではありません。

0
John Dibling

postfixを使用すると、メモリ内のより多くのオブジェクトでインスタンス化されます。一部の人々は、forループで接尾辞演算子を使用する方が良いと言う

0
Yevhen