2011-10-10 15 views
1
char buffer[1000] = {0}; 

これは1000要素をすべて0に初期化しますか?そうでない場合、なぜですか?C++配列を一定時間で初期化する

はOにこれを最適化することができ、コンパイラのように思える(1)次の事実に基づいて:

  1. アレイは固定サイズであり、コンパイル時に知られている配列をスタック上に配置されている
  2. 実行可能ファイルのデータセグメントにこのデータが含まれている可能性があります。これは、すでに0で埋められているデータのまとまりとして(Windows上では)です。

答えはどのコンパイラでも一般的ですが、私は特にWindows上のMSVCコンパイラ(任意のバージョン)でテストされた回答に興味があります。

ボーナスポイント:詳細については、記事、ホワイトペーパーなどへのリンクが大変ありがとうございます。

+1

これはどんなコンテキストですか?静的? – user7116

+4

1つのパラグラフ –

+0

@ n.mでO表記と "コンパイル時間"について話すのは意味がありません。私はコンパイル時間やパフォーマンスのように "コンパイル時間"に言及していません、私はコンパイルの瞬間を表すために "コンパイル時間"を参照しています。 –

答えて

4

グローバルであるかどうかは決して一定ではありません。そのコンパイラが実際にそれを初期化しますが、オペレーティングシステムはすべてのファイルをメモリにロードする必要があります。メモリには、O(n)の時間がかかります。

+1

なぜファイルについて話していますか? –

+0

@RobertDailey:実行ファイル(プログラム)をメモリにロードする必要があるためです。データセグメントに実行可能ファイルに1000個のゼロが割り当てられていても、実行可能ファイルはメモリにマップする必要があり、これは線形時間演算です。 –

+0

ダニが正しいです。配列はメモリ内の0に初期化されるか、またはディスクから読み込まれます。しかし、ディスクからN個のゼロを読み取ることはO(N)でもあります。 –

6

グローバル変数としてのみO(1)にすることができます。ローカル変数(スタック上)の場合はO(n)です.nは配列のサイズです。

スタックは共有メモリであり、常にゼロを常にゼロにしたい場合は、ゼロをアクティブにする必要があります。あなたが定義したような配列は、データセグメントへのポインタとして実装されていません。スタック上の1000個の変数であり、O(1000)で初期化する必要があります。

EDIT:Daniはそうです、私は私のステートメントを修正する必要があります:グローバル配列の場合は、プログラムの開始時に初期化されます。それはO(n)でもあります。

+0

フレーミングが含まれている場合、共通のイディオムは、スタックポインタを移動してスペースを作ってから、後ろに来てローカル変数に値を適用することです。 – user7116

+1

グローバルであっても、オペレーティングシステムがそれをロードする必要がある場合は、私の答え – Dani

+0

を参照してください。データセグメントからのデータが各機能のスタックにコピーされたと考えました。私はこのような低レベルの詳細について専門家ではないが、スタックへの1バッチコピー、すなわち1000バイトをスタックに1つの最適化された操作として 'プッシュ'する配列を考えた。私はそれが各要素のために一押しをしていたことを知らなかった。何とかそれを最適化できるようだね... –

-1

グローバルスタティックの場合、ここでの「定数」はゼロです - コンパイル時に初期化が行われます。

+2

どのようにして、まだ存在しないマシンにも1000個の連続したゼロのブロックを割り振りますか? –

8

機能の中にある場合、いいえ、一定の時間ではありません。

あなたの第2の仮定が正しくない:

「アレイは、おそらく実行可能のチャンクとして(Windowsの場合)実行可能ファイルのデータセグメントでこのデータを含むことができることを意味し、スタック上に配置されていますすでに0で埋められているデータです。

スタックにはまだゼロが入っていません。これは、以前の関数呼び出しから残ったジャンクでいっぱいです。

O(1)でそれを行うことはできません。ゼロにする必要があるからです。

1

アレイはスタック上に配置されているため、実行可能ファイルのデータセグメントにこのデータが含まれている可能性があります(Windowsの場合)。

配列を定義する関数を再度呼び出すとどうなりますか?グローバルDATAセグメントは、関数呼び出しごとにこの配列のコピーを持たなければならず、各関数が独自の配列を持つことができます。コンパイラは、あなたのコードを実行して、最大の再帰が起こることを決める必要があります。

また、プログラム内に複数のスレッドがあり、それぞれがfooを呼び出すとどうなりますか?突然、あなたはDATA内でロックしなければならないものを共有しています。ロックは、初期化を取り除くよりもパフォーマンス上の問題を引き起こす可能性があります。

あまりにも心配しません。ほとんどのプラットフォームでは、メモリをゼロにするというかなり効率的な方法があります。それをプロファイリングして問題を見つけるのでなければ、それを汗ばませないでください。

0

他の人が指摘しているように、仮定2は間違っています。スタック変数は実行時にO(1)時間に割り当てられますが、デバッグビルドを実行している場合を除き、通常は初期化されません。

PUSH ebp 
MOV ebp, esp 
SUB esp, 10 
// function body code goes here 

ここでは、スタックポインタ 'esp'が10だけ減分され、いくつかのローカル関数変数のためのスペースが確保されています。彼らは生まれつきではありません...それはループを必要とします。

This記事は十分に親しみやすいようです。

関連する問題