1

私がクラスを持っているとしましょう:

class ClassX{
   private:
      int* p;
      int i;
   ....
}

そしてどこかで私は:

ClassX x;
.....
//and in a friend function or in a ClassX function
p = (int*) malloc (.....);

次にx、スコープを終了すると、デストラクタが呼び出されます。mallocしかし、それは権利によって割り当てられたメモリを解放しませんか?

そして、私がそれを再定義すると:

ClassX::~ClassX(){ delete [] p; }

クラスのフィールド(つまり、 )mallocに割り当てられたメモリではなく、によって割り当てられたメモリを解放しますか?ip

私は何かが足りないのですか?

ありがとうございました。

4

6 に答える 6

3

簡単なルールは次のとおりです。すべてに対して、malloc正確に1つ存在する必要がありますfree。ごとnewに、正確に1つ存在する必要がありますdelete。すべてに対して、new[]正確に1つ存在する必要がありますdelete[]

あなたの質問に答えるには:

[デストラクタ]はmallocによって割り当てられたメモリを解放しませんか?

正しい。そうではありません。その場合、あなたはを呼び出しmallocましたが、決してfree

[変更されたデストラクタ]は、mallocによって割り当てられたメモリを解放しますが、クラスのフィールドに割り当てられたメモリは解放しませんか?

間違い。メモリを解放しません(この場合freeではなく、を使用する必要があります。はパートナーです。はのパートナーです。パートナーを切り替えることはできません)。delete[]freemallocdelete[]new[]

また、間違っています。クラスのフィールドに割り当てられたメモリを解放します(フィールドが非ポインタ型であると想定します)。オブジェクトが占有するメモリの解放は、デストラクタが戻った後に発生します。

私は何かが足りないのですか?

生のポインタを使用する場合は、三つのルールも理解する必要があります。ただし、さらに良いことに、生のポインターは絶対に使用しないでください。スマートポインタまたはコンテナを使用します。

于 2012-05-03T15:02:46.777 に答える
3

まず、次のことを覚えておいてください。

  1. によって割り当てられたものは、によってmalloc割り当てを解除する必要がありますfree
  2. 使用しないでくださいmalloc
  3. によって割り当てられたものは、によってnew割り当てを解除する必要がありますdelete
  4. によって割り当てられたものは、によってnew[]割り当てを解除する必要がありますdelete[]
  5. deleteすべてに1つ、すべてに1newdelete[]new[]
  6. 上記のいずれも使用しないでください

mallocそうすれば、デストラクタがないと、によって割り当てられたメモリは解放されないと考えるのは正しいことです。上記のルールに従う場合は、割り当てを解除するためにfreeではなくdelete[])を使用する必要があります。

ClassX::~ClassX() { free(p); }

ただし、mallocC ++はオブジェクトのコンストラクターを呼び出さないため、まずC ++で使用するべきではありません。使用する必要がありますnew

ClassX::ClassX() : p(new int) { }

// NOW we use delete since we used new (not delete[] since we didn't use new[])
ClassX::~ClassX() { delete p; }

ただし、その場合は、コピーコンストラクター、コピー代入演算子、ムーブ代入演算子、およびムーブ代入演算子を作成する必要があります。それでは、さらに良い方法を見てみましょう。

class ClassX{
private:
    ClassX();

    std::unique_ptr<int> p;
    int i;
    ....
};

// we have to break rule #6 here
ClassX::ClassX() : p(new int) { }

これで、デストラクタを作成する必要がなくなります。デストラクタが呼び出されると、delete作成したものが自動的に呼び出されるため、スマートポインタに処理させることができます。newそれは私たちを導きます...

あなたの他の質問:

それはmallocによって割り当てられたメモリを解放しますが、クラスのフィールド(つまり、iとp)に割り当てられたメモリは解放しませんか?

それは約1/4正しいです。iとはクラスのメンバーであるためp、囲んでいるクラスの割り当てが解除されると自動的に割り当てが解除され、クラス自体の場合は、デストラクタが呼び出されます。したがってdelete、デストラクタを挿入するnewと、iによって割り当てられたメモリpが処理され、自動的にクリーンアップされ、すべてが正常になります。(間違った割り当て解除機能を使用したため、1/4しか正しくありませんでした。)

つまり、スマートポインターを使用すると、オブジェクトが破棄されたときにスマートポインターのデストラクタが呼び出され、割り当てられたものが自動的に割り当て解除さnewれます。だからあなたもそれについて心配する必要はありません。

これはすべて、クラスの一部としてダイナミックが本当に必要であることを前提としています。intただし、可能であれば、intby値を格納する(ポインタを格納しない)ことをお勧めします。そうすれば、スマートポインタ、割り当て解除、またはその他のものをいじる必要がなくなります。

于 2012-05-03T15:06:34.187 に答える
1

手動でメモリを割り当てる場合は、メモリを解放する必要がありますが、自動的に解放されるわけではありません。

呼び出すmalloc(または、、callocまたはrealloc)場合は、freeそのメモリを呼び出す必要があります。同様に、あなたがそれをnew何かするならdelete、そして。new[]と一致しなければなりませんdelete[]

そうは言っても、あなたはC ++でプログラミングしているので、メモリを手動で管理する正当な理由はめったにありません。スマートポインタを使用します。共有所有権にはstd::shared_ptrを使用し、それ以外の場合はstd::unique_ptrを使用します。

次に、クラスは次のようになります。

#include <memory>

class ClassX{
   private:
      std::unique_ptr<int> p;
      int i;
      ....
};

ClassX::ClassX() : p( new int ) {} /* No need to deallocate p manually */

unique_ptr配列にも部分的な特殊化があることに注意してください。したがってp、配列を指す場合は、次のようにメモリを割り当てることができます。

class ClassX{
   private:
      std::unique_ptr<int[]> p;
      int i;
      ....
};

Class::ClassX() : p ( new int[10] ) {}

また、特にintの配列のような単純なものの場合は、ポインターの処理とstd::vectororの使用を完全に忘れることができます。std::array

于 2012-05-03T15:04:08.337 に答える
1

デストラクタがpを解放する必要があるのは正しいですが、で割り当てる場合mallocは、でメモリを解放する必要がありますfree。または、次の方法でメモリを割り当てることもできます。

x.p = new int[size];

これはあなたのdelete[] p; デストラクタは正しいでしょう。

クラスのメンバー変数に関しては、それらを削除することを心配する必要はありません。オブジェクトがスタックに割り当てられている場合、スタックが巻き戻されるときにそれらは削除されます。クラスがヒープに割り当てられている場合、それらはあなたが作成したときに削除されますdelete x;。いずれにせよ、それらの存続期間は、それらを含むオブジェクトにリンクされています。

于 2012-05-03T15:05:04.453 に答える
1

簡単にするために、私は常にポインターは単なる整数であると自分に言い聞かせています。(システムに応じて、16、32、または64ビット長にすることができます)。これはアドレスの定義に役立つ特別な整数ですが、整数にすぎません

したがって、クラスXを作成すると、2つの「整数」にスペースが割り当てられます。1つはpと呼ばれ、もう1つはiと呼ばれます。そして、クラスが破壊されると、2つの整数といくつかのもののスペースの割り当てが解除されます。

デストラクタは、アドレスを表す特殊な整数pの値を使用して何をしたかを気にしません。作成したのと同じようにメモリを作成することも、乱数を作成することもできます。クラスXを表すメモリでは、すべて同じです。整数のみです。

于 2012-05-03T15:06:20.183 に答える
1

ルールは単純です:

  • で割り当てられたメモリは、newで解放する必要がありdeleteます。
  • で割り当てられたメモリは、new []で解放する必要がありdelete []ます。
  • で割り当てられたメモリは、malloc()で解放する必要がありfree()ます。

割り当て関数によって返されるまったく同じアドレスを割り当て解除関数に渡す必要があることに注意してください。

良い習慣:

  • 本当に必要でない限り、動的割り当てを避けることは常に良い習慣です。
  • 必要に応じて、要件に合ったある種のスマートポインターを使用する必要があります。使用するスマートポインターの決定は、関連する所有権と存続期間のセマンティクスによって異なります。
  • C ++では、使用する必要があることはまれであり、正当な理由がない限り、使用mallocfreeないでください。

また、あなたの場合、あなたのプログラムが正しく機能するためには、三つのルールにも従う必要があります。

于 2012-05-03T15:06:31.970 に答える