web-dev-qa-db-ja.com

delete []はdeleteと同じですか?

IP_ADAPTER_INFO *ptr=new IP_ADAPTER_INFO[100];

自由に使ったら

delete ptr;

そうでない場合、それはメモリリークにつながるのでしょうか?

これはVS2005によって生成された逆アセンブリコードです

; delete ptr;
0041351D  mov         eax,dword ptr [ptr] 
00413520  mov         dword ptr [ebp-0ECh],eax 
00413526  mov         ecx,dword ptr [ebp-0ECh] 
0041352C  Push        ecx  
0041352D  call        operator delete (4111DBh) 
00413532  add         esp,4 

; delete []ptr;
00413535  mov         eax,dword ptr [ptr] 
00413538  mov         dword ptr [ebp-0E0h],eax 
0041353E  mov         ecx,dword ptr [ebp-0E0h] 
00413544  Push        ecx  
00413545  call        operator delete[] (4111E5h) 
0041354A  add         esp,4 
44
Satbir

これがメモリリークにつながるか、ハードディスクをワイプするか、妊娠するか、厄介な鼻の悪魔があなたのアパートの周りを追いかけるか、または明らかな問題なしにすべてが正常に機能するかどうかは未定義です。これは、あるコンパイラではこのようになり、別のコンパイラで変更され、新しいコンパイラバージョンで変更され、新しいコンパイルごとに、月の満ち欠け、気分、または最後の晴れた日にプロセッサを通過したニュートリノの数によって異なります。午後。またはそうではないかもしれません。

そのすべて、そして他の無限の可能性が1つの用語にまとめられています:未定義の振る舞い

近づかないでください。

149
sbi

特定のOSおよびコンパイラでのいくつかの「未定義」の動作の単なる図解。人々が自分のコードをデバッグするのに役立つことを願っています。

テスト1

#include <iostream>
using namespace std;
int main()
{
  int *p = new int[5];
  cout << "pass" << endl;
  delete p;
  return 0;
}

テスト2

#include <iostream>
using namespace std;
int main()
{
  int *p = new int;
  cout << "pass" << endl;
  delete[] p;
  return 0;
}

テスト3

#include <iostream>
using namespace std;
struct C {
  C() { cout << "construct" << endl; }
  ~C() { cout << "destroy" << endl; }
};

int main()
{
  C *p = new C[5];
  cout << "pass" << endl;
  delete p;
  return 0;
}

テスト4

#include <iostream>
using namespace std;
struct C {
  C() { cout << "construct" << endl; }
  ~C() { cout << "destroy" << endl; }
};

int main()
{
  C *p = new C;
  cout << "pass" << endl;
  delete[] p;
  return 0;
}
  • Windows 7 x86、msvc2010。デフォルトのオプションでコンパイルします。つまり、例外ハンドラーが有効になります。

テスト1

pass

テスト2

pass

テスト3

construct
construct
construct
construct
construct
pass
destroy
# Then, pop up crash msg

テスト4

construct
pass
destroy
destroy
destroy
destroy
destroy
destroy
destroy
... # It never stop until CTRL+C
  • Mac OS X 10.8.5、llvm-gcc 4.2、またはgcc-4.8は同じ出力を生成します

テスト1

pass

テスト2

pass

テスト3

construct
construct
construct
construct
construct
pass
destroy
a.out(71111) malloc: *** error for object 0x7f99c94000e8: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
zsh: abort      ./a.out

テスト4

construct
pass
a.out(71035) malloc: *** error for object 0x7f83c14000d8: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
zsh: abort      ./a.out
  • Ubuntu 12.04、AMD64、gcc 4.7

テスト1

pass

テスト2

pass

テスト3

construct
construct
construct
construct
construct
*** glibc detected *** ./a.out: munmap_chunk(): invalid pointer: 0x0000000001f10018 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x7eb96)[0x7fe81d878b96]
./a.out[0x400a5b]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7fe81d81b76d]
./a.out[0x4008d9]
======= Memory map: ========
....
zsh: abort (core dumped)  ./a.out

テスト4

construct
destroy
destroy
destroy
destroy
destroy
destroy
destroy
destroy
...
destroy
destroy
*** glibc detected *** ./a.out: free(): invalid pointer: 0x00000000016f6008 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x7eb96)[0x7fa9001fab96]
./a.out[0x400a18]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7fa90019d76d]
./a.out[0x4008d9]
======= Memory map: ========
...
zsh: abort (core dumped)  ./a.out
14
jichi

PODデストラクタの場合は些細なことであり、それらを呼び出す必要がないため、通常はリークしません。そのため、deleteは配列が占有するメモリの割り当てを解除するだけです。メモリの割り当て解除にはポインタ値のみが必要なので、ヒープに返されます。配列は連続したメモリブロックに対応しているため、単一の要素の割り当て解除であるかのように、割り当て解除を成功させることができます。

ただし、これは未定義の動作であるため、これに依存しないでください。多分それは大丈夫です、多分何か恐ろしいことが起こります、このコンパイラで動作します、別のものでは動作しません、そして多くの人々はエラーを植えてくれてありがとう。

詳細については、 この回答 を参照してください。

7
sharptooth

削除:適切な要素のデストラクタのみポイント(必要な場合)を呼び出し、メモリチャンクを解放します

delete []:配列内の適切な各要素のデストラクタを呼び出し(必要な場合)、メモリチャンクを解放します

5
FranckSpike

新しいT [n]を使用した割り当てでの削除演算子の使用はndefinedであり、コンパイラーごとに異なります。 AFAIK、たとえばMSVCコンパイラはGCCとは異なるコードを生成します。

Aが新しいT [n]を介して割り当てられた配列を指している場合は、delete [] Aを介して削除する必要があります。deleteとdelete []の違いは簡単です。前者はスカラーオブジェクトを破棄し、後者は配列を破棄します。 。

4