6

私がこれを行う場合:

// (1.)
int* p = new int;
//...do something
delete p;

// (2.)
class sample
{
public:
sample(){}
~sample(){}
};
sample* pObj = new sample;
//...do something
delete pObj;

では、C++ コンパイラはどのようにしてオブジェクト フォローイングdeleteが組み込みデータ型またはクラス オブジェクトであることを認識するのでしょうか?

私のもう1つの質問はnew、の配列へのポインターでintあり、その後、delete []コンパイラーは割り当てを解除するメモリブロックのサイズをどのように知るのでしょうか?

4

6 に答える 6

4

渡すポインターの型により、それらの違いを認識します。割り当てたものとは異なるポインター型を渡すことは未定義の動作です (ただし、デストラクタが の場合、基本クラスにポインターを渡すことができますvirtual)コース)。

配列のサイズはどこかに格納されます。一定量のメモリを malloc し、後で解放できる C のようなものです。ランタイムは、以前に割り当てられたサイズを知るために管理する必要があります。

たとえば、バッファが割り当てられる前の要素の数を格納できます。標準では、配列の割り当ての場合に、コンパイラが別の要求サイズを割り当て関数 ( operator new[]) に渡すことを明示的に許可しています。これは、コンパイラがカウントを貼り付け、new式によって返されるアドレスをそのサイズだけオフセットするために使用できます。カウンター。

于 2010-02-27T15:27:05.520 に答える
4
  1. コンパイラは、ポインターの型を認識しているため、ポイント先のオブジェクトの型を認識しています。

    • pは であるint*ため、ポイント先のオブジェクトは になりますint
    • pObjは であるsample*ため、ポイント先のオブジェクトは になりますsample
  2. コンパイラは、指定したオブジェクトが単一のオブジェクトを指しているのか配列 ( ) を指しているのかを認識しません。そのため、配列 の代わりに使用することを覚えておく必要があります。int* pintint[N]delete[]delete

    割り当てを解除するメモリ ブロックのサイズ、および最も重要なこととして、破棄するオブジェクトの数は、new[]それらをどこかに格納するdelete[]ことでわかり、これらの値を取得する場所を知っています。C++ FAQ Lite からのこの質問は、new[]とを実装するための 2 つの一般的な手法を示していdelete[]ます。

于 2010-02-27T15:32:01.783 に答える
1

そうではありません!

プリミティブdelete型の場合は「アクションなし」である型のデストラクタを呼び出すだけです。次に、ポインター::operator delete(または必要に応じてオーバーロードされたバージョン)を渡し、その演算子がメモリを返します (メモリ マネージャーの問題)。つまり、必要に応じて、独自のメモリ マネージャーを C++ で簡単に作成できます。言語は既定で提供されます。

于 2010-02-27T15:27:42.383 に答える
1
  1. コンパイラは、削除されるオブジェクトのタイプを認識し、適切な結果を得るために別のコードを記述します。
    • delete p は、ランタイムの delete を int のサイズで呼び出すことができます。
    • delete pObj は最初に pObj->~sample() を呼び出してから、サンプルのサイズで削除できます
  2. 配列では、配列のサイズに隠された値があると思うので、配列全体が一度に削除される可能性があります。
于 2010-02-27T15:30:11.163 に答える
1

では、C++ コンパイラは、delete に続くオブジェクトが組み込みデータ型またはクラス オブジェクトであることをどのように認識しますか?

コンパイル時に、コンパイラは各オブジェクトの型を追跡し、適切なコードを植えるためです。

私のもう1つの質問は、intの配列へのポインターを新しく作成してから[]を削除した場合、コンパイラーは割り当てを解除するメモリブロックのサイズをどのように知るのでしょうか?

そうではありません。これは、ランタイム システムによって追跡されます。
配列を動的に割り当てると、ランタイム ライブラリはオブジェクトのサイズをオブジェクトに関連付けます。したがって、オブジェクトを削除すると、(関連付けられた値を検索することによって) サイズがわかります。

しかし、それがどのように関連付けを行うのか知りたいと思いますか?
これはシステムに依存し、実装の詳細です。しかし、単純な戦略は、余分な 4 バイトを割り当てて、最初の 4 バイトにサイズを格納し、割り当てられた 4 番目のバイトへのポインタを返すことです。ポインターを削除すると、サイズがポインターの前の 4 バイトであることがわかります。注: システムがこの手法を使用していると言っているわけではありませんが、これは戦略の 1 つです。

于 2010-02-27T15:31:34.657 に答える
0

質問の最初の(非配列)部分については、コンパイラがポインタタイプに基づいて適切なバイト数を割り当て解除するコードを挿入することを示す上記の回答は、明確な回答を提供していません...削除演算子は、1)該当する場合はデストラクタを呼び出し、次に2)「演算子delete()」関数を呼び出します...実際に割り当てを解除するのは演算子deleteです。パート(1)で、コンパイラーが生成したコードが役割を果たしていることがわかります。デストラクタの宛先アドレスを挿入する必要があります。しかし、パート(2)では、割り当て解除を処理する既存のライブラリ関数であるため、データのサイズをどのように知るのでしょうか。グローバル演算子delete(クラスメンバー/オーバーロードされたグローバルバージョンがプログラマーによって定義されていない限り、すべての場合に使用されると思います)は、void*引数の仕様のみを受け入れます。データの先頭を指定するため、データサイズを渡すことさえできません。コンパイラによって生成されたコードのアイデアを示すものや、非配列のグローバル演算子deleteが単にfree()を使用することを示唆するものを読みました。ポインタ型ではなく、データ自体の数バイト前を調べることでデータサイズを認識します。ここで、サイズはnew/mallocによって隠されています。後者は私にとって理にかなっている唯一の解決策ですが、誰かが私を別の方法で啓発することができるかもしれません... サイズはnew/mallocによって隠されています。後者は私にとって理にかなっている唯一の解決策ですが、誰かが私を別の方法で啓発することができるかもしれません... サイズはnew/mallocによって隠されています。後者は私にとって理にかなっている唯一の解決策ですが、誰かが私を別の方法で啓発することができるかもしれません...

于 2010-03-02T02:19:29.930 に答える