Ist delete p wo p ist ein Zeiger auf Array immer ein Speicherleck?

7

Nach einer Diskussion in einem Software-Meeting habe ich herausgefunden, ob das Löschen eines dynamisch zugewiesenen primitiven Arrays mit der einfachen delete einen Speicherverlust verursachen wird.

Ich habe dieses winzige Programm geschrieben und es mit Visual Studio 2008 unter Windows XP kompiliert:

%Vor%

Ich habe dann den Speicherverbrauch meiner Anwendung mithilfe des Task-Managers überwacht. Überraschenderweise wurde der Speicher korrekt zugewiesen und freigegeben. Der zugewiesene Speicher stieg nicht wie erwartet an.

Ich habe mein Testprogramm geändert, um ein nicht-primitives Array zuzuordnen:

%Vor%

Nach 10 Minuten Laufzeit gab es keine nennenswerte Speichererweiterung

Ich habe das Projekt mit Warnstufe 4 kompiliert und keine Warnungen erhalten.

ist es möglich, dass die Visual Studio-Laufzeit die zugewiesenen Objekttypen verfolgt, so dass es zwischen delete und delete[] in dieser Umgebung keinen Unterschied gibt?

    
Eli 09.03.2010, 09:01
quelle

8 Antworten

19

lösche p, wobei p ein Array ist, heißt undefiniertes Verhalten.

Insbesondere, wenn Sie ein Array von Rohdatentypen (ints) zuweisen, hat der Compiler nicht viel zu tun, also verwandelt er es in ein einfaches malloc (), also wird delete p wahrscheinlich funktionieren.

delete p wird normalerweise fehlschlagen, wenn:

  • p war ein komplexer Datentyp - delete p; kann nicht einzelne Destruktoren aufrufen.
  • Ein "Benutzer" überlädt den Operator new [] und löscht [], um einen anderen Heap als regulären Heap zu verwenden.
  • Die Debug-Laufzeit überlädt den Operator new [] und löscht [], um zusätzliche Tracking-Informationen für das Array hinzuzufügen.
  • Der Compiler entscheidet, dass er zusätzliche RTTI-Informationen zusammen mit dem Objekt speichern muss, die p löschen; verstehe nicht, aber lösche [] p; wird.
Chris Becke 09.03.2010, 09:15
quelle
17

Nein, das Verhalten ist nicht definiert. Tu es nicht - benutze delete[] .

In VC ++ 7 bis 9 funktioniert es wenn der fragliche Typ einen trivialen Destruktor hat , aber es könnte aufhören, an neueren Versionen zu arbeiten - übliche Sachen mit undefiniertem Verhalten. Tu es trotzdem nicht.

    
sharptooth 09.03.2010 09:06
quelle
3

Es heißt undefiniertes Verhalten ; es könnte funktionieren, aber Sie wissen nicht warum, also sollten Sie nicht dabei bleiben.

Ich glaube nicht, dass Visual Studio verfolgt, wie Sie die Objekte zugewiesen haben, als Arrays oder einfache Objekte und fügt [] Ihrem Löschen dynamisch hinzu. Es kompiliert wahrscheinlich delete p; zu dem gleichen Code wie wenn Sie mit p = new int zugewiesen haben, und, wie gesagt, aus irgendeinem Grund funktioniert es. Aber Sie wissen nicht warum.

    
Viktor Sehr 09.03.2010 09:06
quelle
3

Eine Antwort ist, dass es Speicherlecks verursachen kann, weil es den Destruktor nicht für jedes Element im Array aufruft. Das bedeutet, dass zusätzlicher Speicher, der Eigentum von Elementen im Array ist, ausläuft.

Die mehr standardkonforme Antwort ist, dass es ein undefiniertes Verhalten ist. Beispielsweise hat der Compiler das Recht, unterschiedliche Speicherpools für Arrays zu verwenden als für Nicht-Array-Elemente. Die neue Einwegmethode, aber das Löschen der anderen Datei, kann zu einer Beschädigung des Heapspeichers führen.

Ihr Compiler kann garantieren, dass der Standard dies nicht tut, aber das erste Problem bleibt bestehen. Für POD-Elemente, die keinen zusätzlichen Speicher (oder Ressourcen wie Dateihandles) besitzen, könnten Sie OK sein.

Auch wenn es für Ihren Compiler und Datenelemente sicher ist, tun Sie es trotzdem nicht - es ist auch irreführend für jeden, der versucht, Ihren Code zu lesen.

    
Steve314 09.03.2010 09:52
quelle
2

nein, Sie sollten delete[] verwenden, wenn Sie mit Arrays arbeiten

    
knittl 09.03.2010 09:06
quelle
2

Wenn Sie delete verwenden, werden die Destruktoren der Objekte im Array nicht aufgerufen. Während es möglicherweise wie beabsichtigt funktioniert, ist es undefiniert, da es einige Unterschiede gibt, genau wie sie funktionieren. Sie sollten es also nicht verwenden selbst für integrierte Typen .

    
Yacoby 09.03.2010 09:09
quelle
1

Der Grund dafür, Speicher nicht auslaufen zu lassen, liegt darin, dass das Löschen in der Regel auf dem freien Speicher basiert, der bereits weiß, wie viel Speicher er frei braucht. Es ist jedoch unwahrscheinlich, dass der C ++ Teil korrekt bereinigt wird. Ich wette, dass nur der Destruktor des ersten Objekts aufgerufen wird.

    
Jan 09.03.2010 09:16
quelle
1

Die Verwendung von delete mit [] weist den Compiler an, den Destruktor für jedes Element des Arrays aufzurufen. Wenn Sie delete [] nicht verwenden, können Speicherverluste auftreten, wenn sie in einem Array von Objekten verwendet werden, die dynamische Speicherzuweisungen wie folgt verwenden:

%Vor%     
sergiom 09.03.2010 09:21
quelle

Tags und Links