2009-08-20 5 views
23

私の同僚は、オブジェクト型の事前増分よりも後増分よりも効率的であると主張しています。++イテレータとイテレータ++のパフォーマンスの違いは?

std::vector<std::string> vec; 

... insert a whole bunch of strings into vec ... 

// iterate over and do stuff with vec. Is this more efficient than the next 
// loop? 
std::vector<std::string>::iterator it; 
for (it = vec.begin(); it != vec.end(); ++it){ 

} 

// iterate over and do stuff with vec. Is this less efficient than the previous loop? 
std::vector<std::string>::iterator it; 
for (it = vec.begin(); it != vec.end(); it++){ 

} 
+1

http://stackoverflow.com/questions/24901/is-there-a-performance-difference-between-i--i-in-cの複製にかなり近いです。この質問は反復子を指定しますが、リンクされた質問はより一般的です。 – Eclipse

+0

リンクには素晴らしい答えがあります。 – Matt

答えて

48

ポストインクリメントそれがインクリメントされる前に、イテレータが持っていた値を返す必要があります。以前の値を適切なインクリメントで変更する前にどこかにコピーする必要があるので、それを返すことができます。余分な作業は少しでも多すぎるかもしれませんが、単にインクリメントを実行してちょうど変更された値を返すことができるプリインクリメントと比べて、ゼロより小さくすることはできません。等が必要です。

あなたは特に増分を持っていなければなりません(何らかの方法で「増分前の値」を使用しているからです)、常に増分を使用してください。ポストインクリメントプリインクリメントの用語で定義されて

class X 
{ 
    X operator++(int) // Post increment 
    { 
     X tmp(*this); 
     this->operator++(); // Call pre-increment on this. 
     return tmp; 
    } 
    X& operator++() // Pre increment 
    { 
     // Do operation for increment. 
     return *this; 
    } 
}; 

お知らせ:

+0

標準イテレータが遅くなる理由は本当にありません。標準で指定されているように、std :: behavesのものを想定するコンパイラではないので、組み込み型に対しても同じ最適化を行います。 – derobert

+2

derobert:はい、できます。すべてのイテレータ・タイプがそのような最適化を行うのに十分単純ではありません。オブジェクトが "十分な"大きさであれば、減速することができます。間違いなくほぼ間違いなく、タイトなループでこのイディオムを使用します。 – quark

+0

民俗風俗の質問の一種。実際の詳細を聞いてうれしいです。 –

5

を見て、私はこれを行うために使用されます。それは1998/1999年に私がVisual Studioの多くのプログラムで約10%増やすのを助けてくれました。その直後に、彼らはオプティマイザを修正しました。ポストインクリメント演算子は、スタック上に変数を作成し、値をコピーし、ソースをインクリメントした後、変数をスタックから削除しました。オプティマイザが使用されていないことを検出すると、そのメリットはなくなりました。

ほとんどの人がそのようにコーディングを停止しませんでした。 :)それは私に数年かかった。

オブジェクトの場合、どのように動作するかわかりません。ポストインクリメントの真の実装にコピーオペレータが必要であると私は考えている。コピーを作成し、そのコピーを操作に使用し、ソースを増やす必要があります。

ヤコブ

16

デフォルトのインクリメント演算子は、次のようになります。だからポストインクリメントは、同じ仕事といくつかの余分なことを加えたものです。通常、これはコピーを作成し、コピーを介してコピーを返します(プリインクリメントは参照によって返されますが、ポストインクリメントはできません)。

+1

あなたはそこに2つの接尾辞を持っています。 –

+0

2つの接尾辞をどういう意味ですか?私はポストとプレを見ることができます。私はそれをテストしました。 – flyjohny

+0

@flyjohny:コメントは1年前で、訂正する前に投稿の最初のバージョンを参照しました:http://stackoverflow.com/posts/1304020/revisions –

3

事前増分の代わりにポストインクリメントを呼び出すため、実際にパフォーマンス上の問題が発生している場合を除き、真剣に対応してください。パフォーマンスの差異はまったくまれな状況にしかなりません。例えば


更新

に、お使いのソフトウェアは、気候シミュレーションで、operator++はシミュレーションがステップを前方に移動させる場合(つまり、++simulationではsimulation++ながら、あなたのシミュレーションの次のステップを与えますシミュレーションの現在のステップのコピーを作成し、シミュレーションを進めてからコピーします)、パフォーマンスが問題になります。

より現実的には、コメントでは、当初の質問者は、(明らかに)リアルタイム要件を持つ組み込みプロジェクトについて議論していると述べています。その場合は、具体的な実装を実際に調べる必要があります。私は真剣に疑問に思うほど遅く、std::vectorを使って繰り返しますが、この点についてはSTLの実装をベンチマークしていませんが、プリインクリメントではなくポストインクリメントを使用しています。


性能上の理由から1つを選択しないでください。分かりやすい/メンテナンスの理由から、もう一方を選択してください。個人的には、私は通常、増分する前の値が何であったのか分からないので、デフォルトでプリインクリメントにしています。

i++の代わりに++iが表示されたときに脳が爆発する場合は、別の作業行程に入ることを検討する必要があります。

+2

正しい。しかし、プリインクリメントを好むべきです。その理由は、誰かがシステムの基礎となるタイプを変更した場合、戻ってすべてのポストインクリメントが効率的であるかどうかを確認する必要がないからです。したがって、保守性のためには、事前増分を優先する必要があります。 –

+0

私はまだパフォーマンスの問題はありませんが、私が取り組んでいるシステムでパフォーマンスを考えるのに費やしています。このソフトウェアは、1秒間に何千ものコールを処理するテレコム部門で動作しています。私は、パフォーマンスの違いがあるかどうかを尋ねるだけだと思っていました。 – Matt

+0

非常に正確です。しかし、問題は、どちらがより効率的であるかを知りたがっていました。 – n002213f

0

私はこれが航空で「ハンガー飛行」のようなものだと知っています。純粋に学問的なものだと確信しています。違いがある場合は、コードを再考する必要があります。

例:

パーソン:私は、私はパフォーマンスチューニングに関するいくつかの質問に与えた、そしてそれはこのように行ったいくつかの答えにコメントを得た私は、ランダムに停止し、コールスタックを見てのあなたの方法を試してみました。私はそれを何度もやったが、それは意味をなさない。常に、イテレータをインクリメントするコードは深いです。何が良い?

私は素晴らしいです!ほぼすべての時間がイテレータをインクリメントすることになります。スタックを上にして、どこから来ているのか確認してください。これを単純な整数インクリメントに置き換えると、の大容量ののスピードアップが得られます。

もちろん、イテレータをインクリメントするのが好きかもしれませんが、多くのパフォーマンスがかかっているかどうか調べるのは簡単です。

+0

スタックをランダムに停止するよりも堅牢な方法で同じ情報を得ることができる環境で使用可能なプロファイラはありませんか?サンプリング・プロファイラーは基本的に同じで、より頻繁に、そして自動的に行います。 – Blaisorblade

+0

@Blaisorblade:PDFスライドショー* [here](http://sourceforge.net/projects/randompausedemo/files/)*をご覧ください。プロファイラは低い期待に基づいています。 –

+0

私はそれを試してみる必要がありますが、あなたの考えはある意味があります。 – Blaisorblade

4

私はそれがまともなオプティマイザを持つコンパイラとの違いは何もないことを読んだ。ループ全体のロジックは両者で同じなので、良いインクリメンタルなプログラミング習慣としてプリインクリメントを使用することは理にかなっています。そうすれば、プログラマーが "準最適"コンパイラに遭遇すると、最良の結果が保証されます。