1

私は最近、私たちのコードの多くの場所が次のようなことをしていることを発見しました:

int * int_array = new int[1000];

// ... do things with int_array

delete int_array;

delete []もちろん問題は、通常の演算子ではなく、演算子を使用する必要があることdeleteです。

謎は: このコードは、Windows の Visual Studio 2003 と 2005、および OS X の GCC / clang でコンパイルされたとき、文字通り何年もの間機能していました。

私が理解しているように、コンパイラに「間違った」方法でメモリの割り当てを解除するように指示しています。通常、そうすると、何かひどいことが起こり、プログラムがクラッシュします。なぜこれが起こらないのですか?現代のコンパイラは自動的に「正しいことをする」のでしょうか、それとも基本的な型やその他の何かにとって問題にならないほど十分に正しいことでしょうか? このコードは何年にもわたって使用されており、複数の異なるオペレーティング システムで何千もの顧客によって使用されてきたため、単純に幸運だったとは言えません。

間違ったことをする言い訳を求めているのではなく、間違ったことをしても問題にならない理由を理解しようとしているだけです。:)

4

5 に答える 5

5

これは未定義の動作の性質です。意図したとおりに動作する可能性があります。問題は、コンパイラ、オペレーティング システム、ライブラリ、または CPU の次のバージョンでは、まったく異なる動作をする可能性があることです。

ほとんどの場合、次の 2 つの理由で問題を回避できます。

  1. intデストラクタがありません。したがって、配列内の各要素を正しく破棄できなくても、何の影響もありません。

  2. このプラットフォームでは、同じアロケーターnewを使用します。new[]したがって、間違ったアロケーターにブロックを返すことはありません。

于 2013-02-03T20:04:07.390 に答える
3

何が起こるかを順を追って見ていきましょう (例外は無視します):

int *foo = new int[100];

100*sizeof(int)これにより、メモリのバイトが割り当てられint::int()、配列内の要素ごとに 1 回、100 回呼び出されます。

は組み込み型であるためint、自明なコンストラクターがあります (つまり、何もしません)。

さて、どうですか:

delete foo;

これにより、 が指すアドレスが呼び出さint::~int()れ、 が指すfooメモリが削除されfooます。繰り返しますintが、組み込み型であるため、簡単なデストラクタがあります。

これを次と比較してください。

delete [] foo;

int::~int()が指す配列内の各項目を呼び出しfoo、foo が指すメモリを削除します。

ここでの基本的な違いは、要素 1..99 が破棄されないことです。それintは問題ではなく、それがおそらく既存のコードが機能する理由です。実際のデストラクタを持つオブジェクトの配列の場合、より多くの誤動作が見られます。

fooPSほとんどの実装では、array-newで割り当てた場合でも、書き込むと、が指すメモリのブロック全体が削除されdelete foo;ますが、それを当てにするのはばかげています。

于 2013-02-04T04:50:49.867 に答える
1

通常のdelete演算子は、アロケータによっては、実際には配列からすべてのメモリを解放する場合がありますが、実際の問題は、配列要素に対してデストラクタを実行しないことです。

于 2013-02-03T20:01:13.547 に答える
1

これは動作しません。せずに配列を削除すると、[]メモリリークが発生します。アプリケーションを長時間実行すると、パフォーマンスに影響します。短期間のプログラムの場合、問題はありません。

注意すべきもう 1 つのことはdelete、によって割り当てられたすべてのメモリが破棄されることnewです。new(not new [])によって配列を割り当てた場合は、それdeleteを破棄するために使用できます。

于 2013-02-03T20:00:15.467 に答える
1

999 * sizeof(int)これによってプログラムがクラッシュすることはありませんが、そのたびにメモリのバイト数がリークします。

于 2013-02-03T20:00:27.483 に答える