Est-ce que delete est égal à supprimer?

IP_ADAPTER_INFO *ptr=new IP_ADAPTER_INFO[100]; 

si je libre en utilisant

 delete ptr; 

Cela conduira-t-il à une fuite de mémoire, sinon alors 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 

Si cela conduit à une fuite de mémoire, efface votre disque dur, vous met enceinte, fait des méchants démons Nasal vous pourchasser dans votre appartement, ou laisse tout fonctionner sans problèmes apparents, n’est pas défini. Cela peut être ainsi avec un seul compilateur et changer avec un autre, changer avec une nouvelle version du compilateur, avec chaque nouvelle compilation, avec les phases de lune, votre humeur, ou selon le nombre de neusortingnos qui ont traversé le processeur après midi. Ou peut-être pas.

Tout cela et un nombre infini d’autres possibilités sont regroupés dans un seul terme: Comportement indéfini :

Restez loin de ça.

Juste une illustration de certains comportements “non définis” sur certains systèmes d’exploitation et compilateurs. J’espère que cela pourrait être utile pour les gens de déboguer leur code.

Test 1

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

Test 2

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

Test 3

 #include  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  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. Comstackr avec les options par défaut, c'est-à-dire que le gestionnaire d'exceptions 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èrent 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 

En général, cela ne fuit pas car, dans le cas de POD, les destructeurs sont sortingviaux et il n’est pas nécessaire de les invoquer. delete simplement la mémoire occupée par le tableau. La désallocation de la mémoire ne nécessite qu’une valeur de pointeur pour qu’elle soit renvoyée au tas. Le tableau utilise un bloc de mémoire contigu et la désallocation peut être réussie comme s’il s’agissait d’une désallocation d’un seul élément.

Mais ne comptez pas sur cela car c’est un comportement indéfini. Peut-être que cela fonctionne bien, peut-être que quelque chose d’horrible se produit, fonctionne sur ce compilateur, ne fonctionne pas sur un autre et de nombreuses personnes vous remercient d’avoir semé une erreur.

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

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

Si A pointe sur un tableau qui a été alloué via new T [n], alors vous devez le supprimer via delete [] A.

Pourquoi?

La différence entre delete et delete [] est simple: le premier détruit un object scalaire et le second détruit un tableau.

Plus d’infos ici et ici .

MISE À JOUR 1 (incorrecte):

Si vous utilisez delete (et non delete []) lors de l’allocation avec new T [n], seul le premier élément est libéré alors que d’autres ne sont pas déstructurés, ce qui entraînera une fuite de mémoire . Pourquoi? C’est ainsi que Bjarne Stroustrup et d’autres ont conçu le langage. Et ce n’est pas différent du compilateur. Si un compilateur désalloue la manière différente, il ne suit simplement pas la norme . Le langage de programmation C ++ , chapitres 6.2.6.2 et 19.4.5.

MISE À JOUR 2 (correct):

J’admets mon erreur sur le comportement de l’utilisation de l’opérateur de suppression sur les allocations avec le nouveau T [n]. En lisant le document mentionné, je n’ai pas trouvé la description exacte, donc je suppose que dans cette situation, le comportement sera indéfini et variera d’un compilateur à l’autre. AFAIK, le compilateur MSVC par exemple produira un code différent de GCC. Veuillez ignorer la mise à jour 1 .

Pour le tableau de POD, il ne fera pas de fuite (avec le plus grand nombre de compilateurs). Par exemple, MSVC génère un code identique pour supprimer et supprimer [] pour le tableau de POD .

Personnellement, je pense que C / C ++ pourrait être sans opérateur delete []. Le compilateur connaît la taille de l’object et la taille de la mémoire allouée est connue à l’exécution. Il est donc très simple de savoir si un tableau de pointeurs est ou non et de disposer de la mémoire correctement.

MODIFIER:

Ok les gars. Pouvez-vous tester auprès de votre compilateur et dire s’il fuit?

Essayez de penser en tant que développeur de compilateur. Nous avons nouveau , nouveau [] , supprimer , supprimer [] . Chaque nouveau a sa propre suppression . Semble parfait et complet. Voyons ce qui se passe quand vous appelez delete [] ?

 1. call vector destructor for an object 2. actual free memory 

Qu’est-ce qu’un destructeur pour POD ? Rien! Donc, appeler delete pour un tableau de POD ne fuira pas! Même si cela brise la norme. Même si ce n’est pas recommandé.

EDIT2:

Ceci est le code de désassemblage généré par VS2008:

 operator delete[]: 78583BC3 mov edi,edi 78583BC5 push ebp 78583BC6 mov ebp,esp 78583BC8 pop ebp 78583BC9 jmp operator delete (78583BA3h)