46 votes

Est-ce que delete [] est égal à supprimer?

 IP_ADAPTER_INFO *ptr=new IP_ADAPTER_INFO[100];
 

si je libère en utilisant

 delete ptr;
 

mènera-t-il à une fuite de mémoire, sinon pourquoi?

Ceci est le code de désassemblage généré par 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
 

154voto

sbi Points 100828

Si cela conduit à une fuite de mémoire, efface le contenu de votre disque dur, vous met enceinte, qui rend méchant Nasale Démons vous chasser autour de votre appartement, ou permet à tout fonctionne très bien avec pas de problèmes apparents, n'est pas défini. Il pourrait être de cette façon avec un compilateur, et le changer avec un autre, changer avec une nouvelle version de compilateur, avec chaque nouvelle compilation, avec des phases de la lune, de votre humeur ou selon le nombre ou les neutrinos qui est passé par le processeur sur la dernière après-midi ensoleillé. Ou il ne pourrait pas.

De tout cela, et un nombre infini d'autres possibilités sont mis en un seul terme: un comportement Indéfini:

Juste rester loin de lui.

14voto

jichi Points 561

Juste une illustration de certaines "undefined" comportements sur certains Systèmes d'exploitation et les compilateurs. Espérons qu'il pourrait être utile pour les personnes à déboguer leur code.

Test 1

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

Test 2

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

Test 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;
}

Test 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, msvc 2010. Compiler avec les options par défaut, c'est à dire au gestionnaire d'exception est activé.

Test 1

pass

Test 2

pass

Test 3

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

Test 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 ou gcc-4.8 générer la même sortie

Test 1

pass

Test 2

pass

Test 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

Test 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

Test 1

pass

Test 2

pass

Test 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

Test 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

7voto

sharptooth Points 93379

Il sera normalement pas de fuite, car en cas de POD destructeurs sont triviales et il n'y a pas besoin d'invoquer alors delete seulement libère la mémoire occupée par le tableau. Libération mémoire, il suffit de la valeur du pointeur de sorte qu'il sera retourné au tas. Le tableau accopies un bloc contigu de mémoire et donc la libération de la mémoire peut être atteint, comme si c'était une libération de la mémoire d'un seul élément.

Mais ne comptez pas sur cela, car c'est un comportement indéterminé. Ça marche peut-être bien, peut-être que quelque chose d'horrible se produit, fonctionne sur ce compilateur, ne fonctionne pas sur l'autre, et beaucoup de gens je vous remercie pour la plantation d'une erreur.

Voir cette réponse pour plus de détails.

5voto

Andrejs Cainikovs Points 7758

Si Un des points à un tableau qui a été allouée par new T[n], alors vous devez le supprimer via delete[] A.

Pourquoi?

La différence entre delete et delete[] est simple - l'ancien détruit par un scalaire de l'objet et de l'autre détruit un tableau.

Plus d'infos ici et ici.

Mise à JOUR de 1 (mauvais):

Si vous utilisez supprimer (et pas delete[]) tout en allouant avec de nouveaux T[n], seul le premier élément est libéré, tandis que d'autres ne sont pas destructorized, qui va conduire à des fuites de mémoire. Pourquoi? C'est la façon de Bjarne Stroustrup et d'autres avaient conçu la langue. Et il n'est pas le compilateur divers. Si un compilateur libère les différentes manière, c'est juste pas la norme. Le Langage de Programmation C++ , chapitres 6.2.6.2 et 19.4.5.

Mise à JOUR 2 (bon):

Je suis d'admettre mon erreur sur le comportement de l'aide de la suppression de l'opérateur sur les crédits nouveaux T[n]. La lecture de ce document, je n'ai pas trouvé la description exacte donc je suppose que dans ce cas, le comportement est indéfini et varient en fonction du compilateur de compilateur. Autant que je sache, MSVC compilateur, par exemple la production de différents code de GCC. S'il vous plaît ignorer la mise à JOUR 1.

5voto

FranckSpike Points 26

delete : appelle le destructeur approprié uniquement pour l'élément pointé (si nécessaire), puis libère le bloc de mémoire

delete [] : appelle les destructeurs appropriés pour chaque élément de son tableau (si nécessaire), puis libère le bloc de mémoire

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X