2009-06-10 16 views
8

重複の可能性:How does delete[] "know" the size of the operand array?delete []は配列のサイズをどのように知っていますか?


How does the standard new operator work in c++?
How does delete[] “know” the size of the operand array?

デュープ私が割り当てられたメモリのサイズから[]の数字を削除する方法好奇心旺盛です。私が次のようなことをしたとき:

int* table = new int[5]; 
delete[] table; 

私はテーブルのメモリが解放されていることを理解しています。しかし、別のテーブルへのポインタを再割り当てした場合はどうなりますか?

int* table = new [5]; 
int* table2 = new [9]; 
table = table2; 
delete[] table; 

サイズ5または9のテーブルを解放しますか?私はnew []とdelete []がそのサイズに関する情報をどのように共有しているかに興味があります。あるいは、私はここに欠かせないものを逃しているかもしれないC++よくあるご質問liteの回答の

+0

重複している(多かれ少なかれ)http://stackoverflow.com/questions/377178/how-does-the-standard-new-operator-work-in-c/377208 –

+3

私は同意しません。これはより具体的です。 –

+0

補足として、これは回答に記載されているとおり、これは実装固有のものです。 これは、配列のサイズを抽出する方法、コンパイラからコンパイラ、コンパイラのバージョンからコンパイラのバージョンに変わる可能性があるためです。 –

答えて

10

これは、サイズ9の配列を削除します。 ポインタが指す配列を削除します。

サイズ情報がどのように格納されているかは不明であるため、各コンパイラは異なる方法で実装するかもしれませんが、一般的な方法は配列の前に余分なブロックを割り当てることです。つまり、これを実行すると、実際には6つの整数の配列が割り当てられ、最初の要素に配列のサイズが格納されます。次に、2番目の要素へのポインタを返します。だからサイズを見つけるために、delete []は基本的にテーブル[-1]を読まなければなりません。

これは一般的な方法ですが、言語標準ではにする必要があります。ちょうどそれは仕事する必要があります。

もう1つのアプローチは、配列のアドレスを一部のグローバルハッシュテーブルのキーとして使用することです。正しい結果が得られる限り、どのような方法でも有効です。

+0

ありがとうございます。この説明は私には大変意味があります。私は受け入れられた答えとして複数の答えを選ぶのが好きでしたが。 – Lucas

16

Section 16.14この:

これを行う 2つの人気の方法があります。両方のテクニックは商用コンパイラで にあり、 にはどちらもトレードオフがあり、いずれも ではありません。これらの技術は、以下のとおりです。

* Over-allocate the array and put n just to the left 
    of the first Fred object. 
* Use an associative array with p as the key and n as the value. 
+1

連想配列でコンパイラを1つ引用できますか? – curiousguy

+0

@curiousguy FAQのリンクによると、CFrontはこれを次のように使用しています。 http://www.parashift.com/c%2B%2B-faq-lite/compiler-dependencies.html#faq-38.8 –

+0

15年前に既に無関係だった現代のテンプレートは、[1991年の最後のリリース](http://www.softwarepreservation.org/projects/c_plus_plus/index.html#cfront): "_Bjarne Stroustrupノート、"警告Cfront 3は標準より前のものであり、使用を強く推奨せず、それ以上の開発が行われている可能性があります。 "_" – curiousguy

0

私の推測では、新しい[]は、実際にそれはそうよりも多くのデータを割り当てていることです。おそらく、配列内にいくつの項目があるかを示すポインタが返される前に、数バイトがあります。

4

これはどのようにコンパイラ固有の詳細です。しかし、メモリ破損がないと仮定してdelete []を呼び出すと、正しい数の要素が常に削除されます。これを達成するにはいくつかの方法がありますが、1つの簡単な方法はメモリ内の長さを隠すことです。

デモンストレーションの目的でこれを実装するためのすてきで簡単な方法があります。あなたのコードが新しいint [10]を呼び出したとします。コンパイラは、10 * sizeof(int)を割り当てる代わりに、(10 * sizefo(int))+ sizeof(size_t)を割り当てます。そして、最初からオフセットされたsize_tのポインタを返します。最初のsize_tスペースの中には、数字10が書き込まれます。次に、delete []を呼び出してポインタを渡すと、コンパイラはsize_tバイトだけ後退し、削除する要素の数を見つけます。

+0

あなたはそれに私を打ち負かす - まったく同じ例を投稿するつもりだった。 – gnud

+0

これは、割り当てられたメモリに隠して、 "ポインタに隠していない"という例です。 –

+0

@ダン、ちょっとタイプミスを修正しました – JaredPar

1

このメカニズムは実装に依存しますが、あなたの例ではポインタを再割り当てすることで "騙され"ません。これは、あなたに指示したのと同じように、サイズ9の配列の割り当てを解除します(この場合、サイズ5の配列には何も指していないので、メモリリークが発生します)。

2

delete []の仕組みは実装に依存しますが、グローバルnew演算子は何らかの方法で割り当てられたメモリに関連付けられます(ほとんどの場合、割り当てられたメモリの前に置かれるか、ルックアップテーブルに格納されます)。ディスクリプタには、割り当てられたメモリの実際のサイズが含まれます。

2番目のコード例では、delete []は9要素のint配列を正しく削除し、元の5要素配列はリークされます。あなたはそのシステムストアこのような構造では、テーブルのサイズを想像

0

struct MemoryAllocated 
    { 
    size_t sizeOfMemory; 
    char* yourData; 
    } 

各タイプのあなたは、いくつかのメモリを割り当てると、システムは「yourData」へのポインタを返します。 そしてそれぞれのタイプがあなたのメモリが「無料」であれば、システムはポインタをシフトして 'sizeOfMemory'を取得します。関連項目:std :: allocator

0

新しい[]/delete []の場合、メモリごとに起こることは、新しい/削除の場合と同じ/同様です...サイズ情報は(大きい)割り当てられたブロック自体。配列にとって面白いのは、サイズ情報を使ってデストラクタを呼び出すオブジェクトの数を知ることです。

関連する問題