Foo* set = new Foo[100];
// ...
delete [] set;
配列の境界をに渡さないでくださいdelete[]
。しかし、その情報はどこに保存されていますか?標準化されていますか?
Foo* set = new Foo[100];
// ...
delete [] set;
配列の境界をに渡さないでくださいdelete[]
。しかし、その情報はどこに保存されていますか?標準化されていますか?
回答:
ヒープにメモリを割り当てると、アロケータは割り当てたメモリの量を追跡します。これは通常、割り当てられたメモリの直前の「ヘッド」セグメントに格納されます。そうすることで、メモリを解放するときに、デアロケータは解放するメモリの量を正確に把握します。
free
割り当て解除するメモリの量がどのようにわかるか」です。はい、メモリブロックサイズはmalloc
(通常はブロック自体)によって「どこかに」格納されfree
ます。ただし、new[]
/ delete[]
は別の話です。後者は基本的にmalloc
/の上で動作しfree
ます。new[]
また、が作成した要素の数を(とは無関係にmalloc
)メモリブロックに格納し、後でdelete[]
その数を取得して使用して、適切な数のデストラクタを呼び出すことができるようにします。
malloc
)と要素数(によるnew[]
)。前者は後者を計算するために使用できないことに注意してください。一般に、メモリブロックのサイズは、要求されたサイズの配列に実際に必要なサイズよりも大きくなる可能性があるためです。また、配列要素カウンタは、自明でないデストラクタを持つ型にのみ必要であることにも注意してください。自明なデストラクタを持つ型の場合、カウンタはによって格納されnew[]
ず、もちろんによって取得されませんdelete[]
。
コンパイラのアプローチの1つは、もう少し多くのメモリを割り当てて、head要素に要素の数を格納することです。
それがどのようにできるかの例:
ここに
int* i = new int[4];
コンパイラはsizeof(int)*5
バイトを割り当てます。
int *temp = malloc(sizeof(int)*5)
最初のsizeof(int)
バイトに「4」を格納します
*temp = 4;
そして設定 i
i = temp + 1;
したがってi
、5ではなく4要素の配列を指します。
そして削除
delete[] i;
次のように処理されます。
int *temp = i - 1;
int numbers_of_element = *temp; // = 4
... call destructor for numbers_of_element elements
... that are stored in temp + 1, temp + 2, ... temp + 4 if needed
free (temp)
これは、コンパイラー固有であるようにC ++標準で定義されています。つまり、コンパイラの魔法です。それは、少なくとも1つの主要なプラットフォームでの重要な配置制限によって破られる可能性があります。
によってdelete[]
返されるポインターに対してのみ定義されることを実現することにより、可能な実装について考えることができますnew[]
。これは、によって返されるポインターとは異なる場合がありますoperator new[]
。実際の実装の1つは、配列カウントをによって返される最初のintに格納しoperator new[]
、それをnew[]
超えてオフセットされたポインタを返すことです。(これが重要な配置が壊れる理由new[]
です。)
operator new[]/operator delete[]
!= であることに注意してくださいnew[]/delete[]
。
さらに、これは、Cがによって割り当てられたメモリのサイズを知る方法と直交していますmalloc
。
なぜなら、「削除」される配列は、「new」演算子の1回の使用で作成されているはずだからです。「新しい」操作は、その情報をヒープに配置する必要があります。そうでなければ、newの追加の使用はどのようにヒープが終了するかを知るでしょうか?
標準化されていません。Microsoftのランタイムでは、新しい演算子はmalloc()を使用し、削除演算子はfree()を使用します。したがって、この設定でのあなたの質問は次と同等です:free()はどのようにブロックのサイズを知るのですか?
裏側で、つまりCランタイムで、簿記が行われています。
これは、最初に考えるよりも興味深い問題です。この応答は、1つの可能な実装に関するものです。
まず、あるレベルではシステムはメモリブロックを「解放」する方法を知っている必要がありますが、基礎となるmalloc / free(通常はnew / delete / new [] / delete []が呼び出す)は必ずしも正確にどのくらいのメモリを覚えているとは限りません要求した場合、切り上げられる可能性があります(たとえば、4Kを超えると、多くの場合、次の4Kサイズのブロックに切り上げられます)。
したがって、メモリブロックのサイズを取得できたとしても、それが小さくなる可能性があるため、新しいメモリ内の値の数はわかりません。したがって、値の数を示す追加の整数を保存する必要があります。
例外として、構築される型にデストラクタがない場合、delete []はメモリブロックを解放する以外に何もする必要がなく、したがって何も格納する必要はありません。