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


91

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

私は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の値をcoutしてメモリアドレス返されますか?
  3. #3は本当に機能しますか?私には機能しているようですが、ポインタはアドレスを格納していません。これはポインタを削除する適切な方法ですか?

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


16
最初の例が表示されないのは、それが間違っているためです。deleteあなただけnew。また、ポインターを削除した後で、ポインター自体をNULLに設定する必要もありません。そこで安全を確保したい場合は、スマートポインタを使用してください。メモリを解放し、何かを保持していないときにアクセスしようとするとエラーが発生します。
chris

うーん、スマートポインターが何であるかはわかりませんが、調べてみます。ありがとうございます。
レオピック

1
一言で言えば、彼らは私が説明したことをします。新しいものを保持するために、あなたは電話をかけreset、それは古いものを解放します。交換せずに解放するには、を呼び出しますrelease。スコープから外れると破棄され、タイプに基づいてメモリを解放できます。std::unique_ptr1人の所有者のみを対象としています。std::shared_ptr最後の所有者がリソースの所有を停止すると、それを解放します。また、例外的に安全です。1つのリソースを割り当てた後で例外が発生した場合、リソースは適切に解放されます。
chris

回答:


165

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には、いくつかのが付属しています。


13
<pedantry>「オンザスタック」は実装の詳細です-C ++が言及を著しく避けている詳細です。より正確な用語は「自動保存期間あり」です。(C ++
11、3.7.3

4
ありがとうございました。a)何が問題だったかを説明し、b)ベストプラクティスを提供していただき、ありがとうございました。
レオピック

6
@Tqnそうではありません。delete myPointer割り当てを解除します*myPointer。それは正しいです。しかしmyPointer、解放されており、UBであるため使用しないでください。そもそもローカル変数であった場合にのみ、スコープの終了後はアクセスできなくなります。
Anirudh Ramanathan 2014

2
@DarkCthulhuありがとう!(私は文字通り)new毎日何かを学びます。(私は安っぽいです!)
Tqn 2014

1
@AmelSalibasicスタック上の変数に関連付けられたメモリは、スコープ外になったときにのみ解放されます。それを割り当てて、NULL後で誤用するのを防ぎます。
Anirudh Ramanathan 2014

23

私はあなたがポインタがどのように機能するかを完全に理解していないと思います。
いくつかのメモリを指すポインタがある場合、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実際には何もせず、エラーは発生しません。


2
おかげで、これは非常に役に立ちました。すべてのポインタを削除する必要があると思いましたが、それが新しいポインタだけのものであるとは知りませんでした。ありがとう。
レオピック

13

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

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

int *some_integers = new int[20000]

これにより、20000の整数にメモリ空間が割り当てられます。スタックのサイズは制限されており、スタックオーバーフローエラーなしで「int」の大きな負荷をいじくり回したい場合があるため、便利です。

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

delete [] some_integers;

お役に立てば幸いです。


1
割り当てられたメモリは他のプログラムが使用するために返されるが、プログラムの実行が終了した後でのみ追加したい。
sk4l 2016年

7

C ++でのルールはすべてのために、ある新しいがあり、削除

  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;

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

1
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
さらに、スタックフレームyoutube.com/watch?v=bjObm0hxIYY、およびポインタに関するyoutube.com/watch?v=Rxvv9krECNwに関するこの講義をご覧ください。
Casper Beyer
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.