web-dev-qa-db-ja.com

C ++でのポインターの削除

コンテキスト:私は頭をポインターに巻き付けようとしていますが、数週間前に学校で見ましたが、今日の練習中に愚かなことに遭遇しましたか?問題、それはあなたにとって非常に簡単かもしれませんが、私はほとんど、またはまったくプログラミングの経験がありません。

ポインターの削除についてSOでかなりの数の質問を見てきましたが、それらはすべて、単純なポインター(または適切な用語)ではなく、クラスの削除に関連しているようです。私が実行しようとしているコード:

#include <iostream>;

using namespace std;

int main() {
  int myVar,
      *myPointer;

  myVar = 8;
  myPointer = &myVar;

  cout << "delete-ing pointers " << endl;
  cout << "Memory address: " << myPointer << endl;

  // Seems I can't *just* delete it, as it triggers an error 
  delete myPointer;
  cout << "myPointer: " << myPointer << endl;
  // Error: a.out(14399) malloc: *** error for object 0x7fff61e537f4:
  // pointer being freed was not allocated
  // *** set a breakpoint in malloc_error_break to debug
  // Abort trap: 6

  // Using the new keyword befor deleting it works, but
  // does it really frees up the space? 
  myPointer = new int;
  delete myPointer;
  cout << "myPointer: " << myPointer << endl;
  // myPointer continues to store a memory address.

  // Using NULL before deleting it, seems to work. 
  myPointer = NULL;
  delete myPointer;
  cout << "myPointer: " << myPointer << endl;
  // myPointer returns 0.

}

だから私の質問は:

  1. 最初のケースが機能しないのはなぜですか?ポインターを使用して削除する最も簡単な使用方法のように思われますか?エラーは、メモリが割り当てられなかったが、「cout」がアドレスを返したことを示しています。
  2. 2番目の例では、エラーはトリガーされませんが、myPointerの値を計算するとstillはメモリアドレスを返しますか?
  3. #3は本当に機能しますか?私には動作しているようです、ポインタはもはやアドレスを保存していません、これはポインタを削除する適切な方法ですか?

長い質問で申し訳ありませんが、これをできるだけ明確にしたかったので、繰り返しますが、私はプログラミングの経験がほとんどないので、素人の言葉を使ってこれに答えることができれば、とても感謝しています!

75
leopic

1&2

myVar = 8; //not dynamically allocated. Can't call delete on it.
myPointer = new int; //dynamically allocated, can call delete on it.

最初の変数がスタックに割り当てられました。 new演算子を使用して、動的に(ヒープ上に)割り当てたメモリでのみdeleteを呼び出すことができます。

3。

  myPointer = NULL;
  delete myPointer;

上記は何もしませんでした。ポインターがNULLを指していたため、何も解放しませんでした。


次のことは行わないでください:

myPointer = new int;
myPointer = NULL; //leaked memory, no pointer to above int
delete myPointer; //no point at all

リークしたメモリ(割り当てた新しいint)を残して、NULLをポイントしました。指していたメモリを解放する必要があります。割り当てられたnew intにアクセスする方法がなくなったため、メモリリークが発生しました。


正しい方法:

myPointer = new int;
delete myPointer; //freed memory
myPointer = NULL; //pointed dangling ptr to NULL

より良い方法:

C++を使用している場合、しないでください生のポインターを使用します代わりに スマートポインター を使用すると、これらのことをほとんどオーバーヘッドなしで処理できます。 C++ 11には 複数 が付属しています。

144

ポインターがどのように機能するかを完全に理解していないと思います。
いくつかのメモリを指すポインタがある場合、次の3つのことを理解する必要があります。
-ポインター(メモリー)によって「ポイントされたもの」があります
-このメモリアドレス
-すべてのポインターのメモリを削除する必要はありません。動的に割り当てられたメモリのみを削除する必要があります(new演算子を使用)。

想像してみてください:

int *ptr = new int; 
// ptr has the address of the memory.
// at this point, the actual memory doesn't have anything.
*ptr = 8;
// you're assigning the integer 8 into that memory.
delete ptr;
// you are only deleting the memory.
// at this point the pointer still has the same memory address (as you could
//   notice from your 2nd test) but what inside that memory is gone!

あなたがやったとき

ptr = NULL;
// you didn't delete the memory
// you're only saying that this pointer is now pointing to "nowhere".
// the memory that was pointed by this pointer is now lost.

C++では、deleteを指すポインターをnullにしようとすることができますが、実際には何もせず、エラーは発生しません。

17
salgadokk

ポインターは、削除する必要がないという点で通常の変数に似ています。関数実行の終了時および/またはプログラムの終了時にメモリから削除されます。

ただし、次のように、ポインタを使用してメモリの「ブロック」を割り当てることができます。

int *some_integers = new int[20000]

これにより、20000整数のメモリスペースが割り当てられます。スタックのサイズは限られているため、スタックオーバーフローエラーなしで大量の「int」を台無しにしたい場合に便利です。

Newを呼び出すたびに、プログラムの最後で「削除」する必要があります。そうしないと、メモリリークが発生し、他のプログラムが使用するために割り当てられたメモリスペースが返されません。これをする:

delete [] some_integers;

お役に立てば幸いです。

11
user3728501

C++には、newごとにdeleteがあるルールがあります。

  1. 最初のケースが機能しないのはなぜですか?ポインターを使用して削除する最も簡単な使用のようです?エラーは、メモリが割り当てられなかったが、「cout」がアドレスを返したと言います

newが呼び出されることはありません。したがって、coutが出力するアドレスは、myVarのメモリ位置のアドレス、またはこの場合myPointerに割り当てられた値です。書くことにより:

myPointer = &myVar;

あなたは言う:

myPointer = myVarのデータが保存されている場所のアドレス

  1. 2番目の例では、エラーはトリガーされませんが、myPointerの値を計算するとメモリアドレスが返されますか?

削除されたメモリの場所を指すアドレスを返します。最初にポインターを作成し、その値をmyPointerに割り当て、2番目に削除し、3番目に印刷するためです。したがって、myPointerに別の値を割り当てない限り、削除されたアドレスは残ります。

  1. #3は本当に機能しますか?私には機能しているようですが、ポインターはアドレスを保存していません。これはポインターを削除する適切な方法ですか?

NULLは0に等しいため、0を削除するため、何も削除しません。そして、それはあなたがしたので0を出力するロジックです:

myPointer = NULL;

等しい:

myPointer = 0;
7
fonZ
  1. スタックに割り当てられた変数を削除しようとしています。これはできません
  2. ポインタを削除しても、実際にはポインタが破壊されることはなく、占有されているメモリだけがOSに返されます。メモリが別の変数に使用されるまで、または操作されるまで、アクセスできます。そのため、削除後にポインターをNULL(0)に設定することをお勧めします。
  3. NULLポインターを削除しても何も削除されません。
4
Hakan Serce
int value, *ptr;

value = 8;
ptr = &value;
// ptr points to value, which lives on a stack frame.
// you are not responsible for managing its lifetime.

ptr = new int;
delete ptr;
// yes this is the normal way to manage the lifetime of
// dynamically allocated memory, you new'ed it, you delete it.

ptr = nullptr;
delete ptr;
// this is illogical, essentially you are saying delete nothing.
1
Casper Beyer