Ich habe gelesen, dass der Destruktor für das erste Element im Array aufgerufen wird, aber der gesamte Speicher freigegeben wird, wie ich beim Debuggen sehen kann
– Satbir
12. Oktober 2009 um 8:40 Uhr
Nein, nur das erste Element wird freigegeben, andere nicht.
– Andrejs Cainikovs
12. Oktober 2009 um 8:45 Uhr
@Andrej: Nein, das ist nicht sicher. Es könnte so passieren, aber vielleicht auch nicht. Bei PODs ist es sogar wahrscheinlich, dass dies nicht der Fall ist. Aber du weißt nie.
– sbi
12. Oktober 2009 um 8:49 Uhr
Was wird wann passieren IP_ADAPTER_INFO hört auf, POD-Typ zu sein? Werden Sie den gesamten Code bearbeiten? Sie haben Ihre Frage mit dem C++-Tag getaggt, also sollten Sie die Verwendung in Betracht ziehen std::vector.
– Kirill W. Ljadwinski
12. Oktober 2009 um 8:52 Uhr
Ich empfehle dringend, diese Frage zu ignorieren und stattdessen zu lesen [delete vs delete[]](stackoverflow.com/questions/4255598/delete-vs-delete), deren Antworten viel treffender sind.
– Theodor Murdock
11. Mai 2016 um 20:31 Uhr
sbi
Ob dies zu einem Speicherleck führt, Ihre Festplatte löscht, Sie schwanger macht, fiese Nasal Demons dazu bringt, Sie durch Ihre Wohnung zu jagen, oder alles ohne offensichtliche Probleme gut funktionieren lässt, ist undefiniert. Das kann bei einem Compiler so sein und bei einem anderen, bei einer neuen Compiler-Version, bei jeder neuen Compilation, bei den Mondphasen, Ihrer Stimmung oder je nach Anzahl der Neutrinos, die am letzten Sonnigen durch den Prozessor gelaufen sind Nachmittag. Oder vielleicht auch nicht.
All das und unendlich viele andere Möglichkeiten werden in einem Begriff zusammengefasst: Undefiniertes Verhalten:
Halte dich einfach davon fern.
Ich würde sagen, dass “undefiniertes Verhalten” “schlecht” ist und vermieden werden sollte, wie Sie sagen. Aber das bedeutet auch, dass es in einigen Fällen tatsächlich zu einem Speicherleck kommt und Sie immer so codieren sollten, dass Sie Worst-Case-Szenarien lösen. Das ist jedenfalls meine Meinung.
– Philipp Ekberg
12. Oktober 2009 um 8:46 Uhr
@Filip: Angenommen, Ihr eigenes Programm ruft undefiniertes Verhalten auf? Ist das eine weiterentwickelte Form der defensiven Programmierung?
– Michael Foukarakis
12. Oktober 2009 um 9:30 Uhr
+1, um richtig zu sein. Apropos wie delete und delete[] verhält sich in einer bestimmten Implementierung einfach falsch. Es ist ein undefiniertes Verhalten: Tu es nicht.
– jalf
12. Oktober 2009 um 10:03 Uhr
jichi
Nur eine Veranschaulichung einiger “undefinierter” Verhaltensweisen auf bestimmten Betriebssystemen und Compilern. Ich hoffe, es könnte für die Leute hilfreich sein, ihren Code zu debuggen.
Prüfung 1
#include <iostream>
using namespace std;
int main()
{
int *p = new int[5];
cout << "pass" << endl;
delete p;
return 0;
}
Prüfung 2
#include <iostream>
using namespace std;
int main()
{
int *p = new int;
cout << "pass" << endl;
delete[] p;
return 0;
}
Prüfung 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;
}
Prüfung 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. Mit Standardoptionen kompilieren, dh Ausnahmehandler ist aktiviert.
Prüfung 1
pass
Prüfung 2
pass
Prüfung 3
construct
construct
construct
construct
construct
pass
destroy
# Then, pop up crash msg
Prüfung 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 oder gcc-4.8 erzeugen dieselbe Ausgabe
Prüfung 1
pass
Prüfung 2
pass
Prüfung 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
Prüfung 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
Ihr Test zeigt immer noch nicht, ob es Speicherlecks geben würde.
– SOFe
30. November 2017 um 6:17 Uhr
scharfer Zahn
Es wird normalerweise nicht lecken, da im Falle von POD-Destruktoren trivial sind und es nicht erforderlich ist, sie so aufzurufen delete gibt nur den vom Array belegten Speicher frei. Die Speicherfreigabe erfordert nur einen Zeigerwert, damit er an den Heap zurückgegeben wird. Das Array nimmt einen zusammenhängenden Speicherblock auf, sodass die Freigabe erfolgreich sein kann, als wäre es die Freigabe eines einzelnen Elements.
Verlassen Sie sich jedoch nicht darauf, da es sich um ein undefiniertes Verhalten handelt. Vielleicht funktioniert es gut, vielleicht passiert etwas Schreckliches, funktioniert auf diesem Compiler, funktioniert nicht auf einem anderen und viele Leute danken Ihnen für das Einpflanzen eines Fehlers.
Siehe diese Antwort für Details.
Weil new T[] kann ein hinzufügen sizeof offset unabhängig von der POD-ness von T, in diesem Fall delete[] wird dies kompensieren. delete würde den Header-Zuordnungsblock um einige Bytes verfehlen, eine (möglicherweise nicht initialisierte) Elementanzahl als Header interpretieren und eine unvorhersehbare Heap-Beschädigung verursachen. Was sich natürlich nur zeigt, wenn der Chef hinschaut.
– MSalter
12. Oktober 2009 um 9:18 Uhr
Sicher, deshalb das Wort meistens Gibt es. Und Haufenkorruption ist kein Leck.
– scharfer Zahn
12. Oktober 2009 um 9:23 Uhr
struct A { void operator delete[](void *p, size_t t) { } }; obwohl struct A ist ein POD, new A[10] wird diese Größe zuweisen und speichern, und delete[] muss es abrufen und an den Operator delete übergeben
– Johannes Schaub – litb
12. Oktober 2009 um 10:34 Uhr
löschen : ruft die entsprechenden Destruktor nur für das Element zeigt (falls erforderlich) und gibt dann den Speicherblock frei
löschen[] : ruft die entsprechenden Destruktoren für jedes Element in seinem Array (falls erforderlich) und gibt dann den Speicherblock frei
Andrejs Cainikovs
Verwenden des Löschoperators für Zuweisungen mit neuem T[n] ist nicht definiert und variiert von Compiler zu Compiler. AFAIK, der MSVC-Compiler zum Beispiel erzeugt einen anderen Code als GCC.
Wenn A auf ein Array zeigt, das über new T allokiert wurde[n]dann müssen Sie es über Löschen löschen[] A. Der Unterschied zwischen löschen und löschen[] ist unkompliziert – Ersteres zerstört ein Skalarobjekt und Letzteres zerstört ein Array.
Niemand (nicht einmal Bjarne, geschweige denn irgendein Björn) hat angegeben, dass nur ein Objekt befreit werden würde. Es ist nicht definiert. (Und wie ich bereits an anderer Stelle sagte, habe ich mit mindestens einem Compiler gearbeitet, der sie alle befreit hat.)
– sbi
12. Oktober 2009 um 8:57 Uhr
dieser Compiler – Ich sehe keinen Verweis auf einen bestimmten Compiler (mehr) ? „Undefiniertes Verhalten“ ist ein ISO-Standardbegriff und bezieht sich nicht auf eine bestimmte Implementierung.
– MSalter
12. Oktober 2009 um 9:14 Uhr
Der C++-Standard sagt ausdrücklich (zumindest in der mir vorliegenden Entwurfsversion vom 13.9.2001), dass ein solches Verhalten undefiniert ist: Bei der ersten Alternative (delete object) soll der Wert des Operanden von delete ein Zeiger auf ein non sein -Array-Objekt oder ein Zeiger auf ein Unterobjekt (1.8), das eine Basisklasse eines solchen Objekts darstellt (Klausel 10). Wenn nicht, ist das Verhalten undefiniert. Bei der zweiten Alternative (Array löschen) soll der Wert des Operanden von delete der Zeigerwert sein, der aus einem vorherigen Array new-expression resultierte.72) Wenn nicht, ist das Verhalten undefiniert.
– Komat
12. Oktober 2009 um 9:32 Uhr
Keines davon existiert in meiner Kopie (C++98). Wie auch immer, der Standard gibt nur an, was Sie vor den Updates gesagt haben: Einer zerstört ein Skalarobjekt, der andere zerstört ein Array. Es tut nicht Sagen Sie, was Sie in Ihrem ersten Update haben, dass, wenn der skalare Löschvorgang für ein Array aufgerufen wird, das erste Objekt zerstört wird. Das ist nicht durch die Norm garantiert. Es ist einfach undefiniert.
– jalf
12. Oktober 2009 um 10:06 Uhr
Danke jalf, sbi, Komat. Du hattest Recht, ich hatte meinen Fehler zugegeben und den Beitrag aktualisiert.
– Andrejs Cainikovs
12. Oktober 2009 um 10:43 Uhr
Für eine Reihe von POD es wird nicht auslaufen (mit den meisten Compilern). Zum Beispiel, MSVC erzeugt identisch Code für löschen und löschen[] für Array von POD.
Persönlich denke ich, dass C/C++ ohne Operator Delete auskommen könnte[]. Der Compiler kennt die Objektgröße und die Größe des zugewiesenen Speichers ist zur Laufzeit bekannt, daher ist es sehr einfach zu wissen, ob es sich um ein Zeigerarray handelt oder nicht, und den Speicher richtig zu verteilen.
BEARBEITEN:
Okay Leute. Können Sie Ihren Compiler testen und sagen, ob er leckt?
Versuchen Sie, als Compiler-Entwickler zu denken. Wir haben Neu, Neu[], löschen, löschen[]. Jeder Neu hat sein eigenes löschen. Scheint perfekt und vollständig zu sein. Mal sehen, was los ist, wenn Sie anrufen löschen[]?
1. call vector destructor for an object
2. actual free memory
Wozu dient der Destruktor POD? Gar nichts! Also anrufen löschen für Array von POD wird nicht auslaufen! Auch wenn es den Standard bricht. Auch wenn es nicht empfehlenswert ist.
EDIT2:
Dies ist ein von VS2008 generierter Disassemblierungscode:
Niemand (nicht einmal Bjarne, geschweige denn irgendein Björn) hat angegeben, dass nur ein Objekt befreit werden würde. Es ist nicht definiert. (Und wie ich bereits an anderer Stelle sagte, habe ich mit mindestens einem Compiler gearbeitet, der sie alle befreit hat.)
– sbi
12. Oktober 2009 um 8:57 Uhr
dieser Compiler – Ich sehe keinen Verweis auf einen bestimmten Compiler (mehr) ? „Undefiniertes Verhalten“ ist ein ISO-Standardbegriff und bezieht sich nicht auf eine bestimmte Implementierung.
– MSalter
12. Oktober 2009 um 9:14 Uhr
Der C++-Standard sagt ausdrücklich (zumindest in der mir vorliegenden Entwurfsversion vom 13.9.2001), dass ein solches Verhalten undefiniert ist: Bei der ersten Alternative (delete object) soll der Wert des Operanden von delete ein Zeiger auf ein non sein -Array-Objekt oder ein Zeiger auf ein Unterobjekt (1.8), das eine Basisklasse eines solchen Objekts darstellt (Klausel 10). Wenn nicht, ist das Verhalten undefiniert. Bei der zweiten Alternative (Array löschen) soll der Wert des Operanden von delete der Zeigerwert sein, der aus einem vorherigen Array new-expression resultierte.72) Wenn nicht, ist das Verhalten undefiniert.
– Komat
12. Oktober 2009 um 9:32 Uhr
Keines davon existiert in meiner Kopie (C++98). Wie auch immer, der Standard gibt nur an, was Sie vor den Updates gesagt haben: Einer zerstört ein Skalarobjekt, der andere zerstört ein Array. Es tut nicht Sagen Sie, was Sie in Ihrem ersten Update haben, dass, wenn der skalare Löschvorgang für ein Array aufgerufen wird, das erste Objekt zerstört wird. Das ist nicht durch die Norm garantiert. Es ist einfach undefiniert.
– jalf
12. Oktober 2009 um 10:06 Uhr
Danke jalf, sbi, Komat. Du hattest Recht, ich hatte meinen Fehler zugegeben und den Beitrag aktualisiert.
Ich habe gelesen, dass der Destruktor für das erste Element im Array aufgerufen wird, aber der gesamte Speicher freigegeben wird, wie ich beim Debuggen sehen kann
– Satbir
12. Oktober 2009 um 8:40 Uhr
Nein, nur das erste Element wird freigegeben, andere nicht.
– Andrejs Cainikovs
12. Oktober 2009 um 8:45 Uhr
@Andrej: Nein, das ist nicht sicher. Es könnte so passieren, aber vielleicht auch nicht. Bei PODs ist es sogar wahrscheinlich, dass dies nicht der Fall ist. Aber du weißt nie.
– sbi
12. Oktober 2009 um 8:49 Uhr
Was wird wann passieren
IP_ADAPTER_INFO
hört auf, POD-Typ zu sein? Werden Sie den gesamten Code bearbeiten? Sie haben Ihre Frage mit dem C++-Tag getaggt, also sollten Sie die Verwendung in Betracht ziehenstd::vector
.– Kirill W. Ljadwinski
12. Oktober 2009 um 8:52 Uhr
Ich empfehle dringend, diese Frage zu ignorieren und stattdessen zu lesen [delete vs delete[]](stackoverflow.com/questions/4255598/delete-vs-delete), deren Antworten viel treffender sind.
– Theodor Murdock
11. Mai 2016 um 20:31 Uhr