2009-10-23 53 views
8

私は2つのことを試してみました:(以下の疑似コード)配列よりもベクトルの初期化が遅い...なぜですか?

int arr[10000]; 
for (int i = 0; i < 10000; i++) 
{ 
    for (int j = 0; j < 10000; j++) 
    { 
     arr[j] = j; 
    } 
} 

vector<int> arr(10000); 
for (int i = 0; i < 10000; i++) 
{ 
    for (int j = 0; j < 10000; j++) 
    { 
     arr[j] = j; 
    } 
} 

私は両方のプログラムを実行し、 "時間" シェルコマンドを使用してタイムアウトしました。プログラム1は5秒で実行され、プログラム2は30秒で実行されます。コンパイラ最適化を有効にして両方のプログラムを実行し、両方のプログラムがほぼ同じ時間(0.38秒)で実行されました。私はこれらの結果に混乱しています。誰かがなぜこれが起こっているのかを私に説明してもらえますか?

ありがとうございます!

+2

これは、最適化*オフ*で5/30秒かかることを意味しますか? – jalf

+0

彼らは全く同じではないことに注意してください。 Vectorはデフォルトでヒープを割り当てますが、配列はスタック上にあります。 – GManNickG

+0

こんにちはjalf、はい、私の質問の一部でした。私はまた、彼らが最適化後に同じ時間にどのように実行されたかによって混乱しました。 – Aishwar

答えて

16

テンプレートの場合、サブスクリプトは演算子[]で行います。最適化をオフにすると、通常は実際の関数呼び出しとして生成され、配列に添字を付けて単純なものに多くのオーバーヘッドを追加します。最適化を有効にすると、インラインで生成され、そのオーバーヘッドが削除されます。

+0

こんにちはジェリー、あなたの答えをありがとう。今は理にかなっている。私は配列で推測すると、[]を使用して演算子[]への呼び出しを行いません。なぜなら、それは「自然な」(より良い単語がないため)型です。従って5/30。 – Aishwar

+0

右 - 組み込み配列の場合、サブスクリプトコードはほぼ確実に*常に*インラインで生成されます。 –

+0

これは、関数呼び出しのオーバーヘッドが実際にどのように加算されるかを示しています。 – Crashworks

8

デバッグモードでは、std::vectorの実装は、使いやすさのために多くの実行時のチェックを提供します。このチェックは、ネイティブ配列では使用できません。たとえば、VC2008では、vectorの例をデバッグモードでコンパイルすると、の場合は、range-checkingでもとなります。

5

最適化されていないベクトルの実装で境界チェックが実行されている場合は、その不一致が考慮されます。

+0

++私の推測は正しいですが、私は彼(または彼女)が知りたがっていました。 –

0

ベクトルarr(10000)を書き込むと、あなたはオブジェクトを作成し、それを関数と呼んでいます...そして、あなたはint arr [10000]を作成するより遅くなります。

0

例では、配列はスタック上にあります。アレイ内のデータにアクセスするには、スタック上のデータにアクセスする必要があります。それは速いです。

一方、vectorがスタック上にある間に、std::vectorのデータが他の場所に割り当てられます(デフォルトでは、ヒープにstd::allocatorで割り当てられます)。 vectorのデータにアクセスするには、ヒープ上のデータにアクセスする必要があります。これは、スタック上のデータにアクセスするよりもずっと遅いです。

あなたはパフォーマンスのペナルティのために何かを得るでしょう。 std::vectorは成長可能ですが、通常の配列は成長できません。また、std::vectorのサイズはコンパイル時定数である必要はありませんが、スタック上の配列のサイズはコンパイル時定数である必要はありません。ヒープ割り当て配列(operator new[]経由)は、コンパイル時定数である必要はありません。ヒープ割り当て配列とstd::vectorを比較すると、パフォーマンスがはるかに近いことがわかります。

int* arr = new int[10000]; 
for (int i = 0; i < 10000; i++) 
{ 
    for (int j = 0; j < 10000; j++) 
    { 
     arr[j] = j; 
    } 
} 

delete[] arr; // std::vector does this for you 
4

これは良い回答ですが、あなた自身で簡単に見つけ出すことができます。

パフォーマンスに6対1の違いがあります。遅いものを実行し、「一時停止」ボタンを押してください。次にコールスタックを調べます。確率は6(83%)のうち5であり、あなたはそれらの余分な秒をどのように費やしているのか正確に分かるでしょう。あなたが望むほど多くの洞察力を得るためには、それを数回してください。

最適化された場合は、プログラム1と同じ操作を行います。最適化されたプログラムよりも13倍遅いため、各ポーズで確率12/13 = 92%の理由がわかります。

これはthis techniqueのアプリケーションです。

+1

私は多くの開発者の心が最初に良いオレのポーズテクニックを見て、特にそれを買わないときに吹き飛んだのを見てきました。そして、もう一つのサーバー時間を費やして、完全なプロファイリングを実行しました。 – DanO

+0

@ダノ:そうです。私はただ言葉を出そうとしているだけです。人々がそれを知らない理由はない。 –

+0

ちょっとマイク、返事をありがとう。私はそれを試してみたいですが、プログラムをコンパイルするためにコマンドライン環境とgccを使用しています(私はこの環境を使い慣れていません)。私はそれを一時停止してスタックトレースを見ることができますか?ありがとう:) – Aishwar

関連する問題