Löschen vs Löschen [] Operatoren in C ++

134

Was ist der Unterschied zwischen deleteund delete[]Operatoren in C ++?

Shreyasva
quelle
Möglicherweise finden Sie diese Frage relevant stackoverflow.com/questions/1913343/…
sharptooth
7
Die Probleme mit delete und delete [] sind ein Grund, warum ich intelligente Zeiger mag und vector<>wann immer ich kann , anstelle eines Arrays.
David Thornley
@DavidThornley Wenn Sie intelligente Zeiger verwenden, müssen Sie den Unterschied in dem Sinne kennen, dass Sie immer noch wissen müssen, nicht zu schreiben, z. B. std::unique_ptr<int>(new int[3])weil es deleteauf dem Array regulär aufruft, was ein undefiniertes Verhalten ist. Stattdessen müssen Siestd::unique_ptr<int[]>
Arthur Tacca

Antworten:

149

Der deleteOperator gibt Speicher frei und ruft den Destruktor für ein einzelnes Objekt auf, mit dem erstellt wurde new.

Der delete []Operator gibt Speicher frei und ruft Destruktoren für ein Array von Objekten auf, mit denen erstellt wurde new [].

Die Verwendung deleteeines von new []oder delete []eines von zurückgegebenen Zeigers newführt zu einem undefinierten Verhalten.

Nick Meyer
quelle
3
Ich frage mich, ob die Verwendung von delete für ein neues [] Array primitiver Typen wie int oder char (kein Konstruktor / Destruktor) notwendigerweise auch zu undefiniertem Verhalten führt. Es scheint, dass die Arraygröße bei Verwendung primitiver Typen nirgendwo gespeichert wird.
Thomiel
21
Wenn der Standard nicht definiert, was passiert, wenn dies getan wird, handelt es sich per Definition um "undefiniertes Verhalten", selbst wenn Ihr Compiler deterministisch das tut, was Sie möchten. Ein anderer Compiler kann etwas ganz anderes tun.
Rob K
Ich habe diesen Fehler gemacht, als ich ein Array von C-Strings wie "char ** strArray" hatte. Wenn Sie ein Array wie ich haben, müssen Sie das Array durchlaufen und jedes Element löschen / freigeben, dann das strArray selbst löschen / freigeben. Die Verwendung von "delete []" auf dem Array, das ich habe, funktioniert nicht, da (wie in den obigen Kommentaren und Antworten hervorgehoben) IT IT DESTRUCTORS aufgerufen wird und nicht jeder Slot tatsächlich freigegeben wird.
Katianie
88

Der delete[]Operator wird zum Löschen von Arrays verwendet. Der deleteOperator wird zum Löschen von Nicht-Array-Objekten verwendet. Es ruft operator delete[]bzw. operator deletefunktioniert, um den Speicher zu löschen, den das Array oder Nicht-Array-Objekt belegt hat, nachdem (eventuell) die Destruktoren für die Elemente des Arrays oder das Nicht-Array-Objekt aufgerufen wurden.

Das Folgende zeigt die Beziehungen:

typedef int array_type[1];

// create and destroy a int[1]
array_type *a = new array_type;
delete [] a;

// create and destroy an int
int *b = new int;
delete b;

// create and destroy an int[1]
int *c = new int[1];
delete[] c;

// create and destroy an int[1][2]
int (*d)[2] = new int[1][2];
delete [] d;

Für das new, das ein Array erstellt (also entweder das new type[]oder newauf ein Array-Typ-Konstrukt angewendet), sucht der Standard operator new[]in der Elementtypklasse des Arrays oder im globalen Bereich nach einem und übergibt die angeforderte Speichermenge. Es kann mehr anfordern, als N * sizeof(ElementType)es möchte (zum Beispiel um die Anzahl der Elemente zu speichern, damit es später beim Löschen weiß, wie viele Destruktoraufrufe ausgeführt werden müssen). Wenn die Klasse deklariert, operator new[]dass zusätzlich zur Speichermenge ein anderer akzeptiert size_twird, erhält dieser zweite Parameter die Anzahl der zugewiesenen Elemente - er kann dies für jeden gewünschten Zweck verwenden (Debuggen usw.).

Für das newObjekt, das ein Nicht-Array-Objekt erstellt, wird operator newin der Klasse des Elements oder im globalen Bereich nach einem gesucht. Es übergibt die angeforderte Speichermenge (genau sizeof(T)immer).

Für die delete[]wird der Elementklassentyp der Arrays untersucht und ihre Destruktoren aufgerufen. Die verwendete operator delete[]Funktion ist die in der Klasse des Elementtyps oder, falls keine vorhanden ist, im globalen Bereich.

Für die delete, wenn der übergebene Zeiger eine Basisklasse des tatsächlichen Objekttypen ist, muss die Basisklasse einen virtuellen Destruktor hat (sonst Verhalten ist nicht definiert). Wenn es sich nicht um eine Basisklasse handelt, wird der Destruktor dieser Klasse aufgerufen und ein operator deletein dieser Klasse oder der globaler operator deleteverwendet. Wenn eine Basisklasse übergeben wurde, wird der Destruktor des tatsächlichen Objekttyps aufgerufen und der operator deletein dieser Klasse gefundene wird verwendet, oder wenn keine vorhanden ist, wird ein globaler operator deleteaufgerufen. Wenn der operator deletein der Klasse einen zweiten Parameter vom Typ hat size_t, erhält er die Anzahl der Elemente, die freigegeben werden sollen.

Johannes Schaub - litb
quelle
18

Dies ist die grundlegende Verwendung von Allocate / DE-Allocate Pattern in c ++ malloc/ free, new/ delete, new[]/delete[]

Wir müssen sie entsprechend verwenden. Aber ich möchte dieses besondere Verständnis für den Unterschied zwischen deleteund hinzufügendelete[]

1) deletewird verwendet, um die Zuweisung von Speicher für ein einzelnes Objekt aufzuheben

2) delete[]wird verwendet, um die Zuordnung des für ein Array von Objekten zugewiesenen Speichers aufzuheben

class ABC{}

ABC *ptr = new ABC[100]

Wenn wir sagen new ABC[100], kann der Compiler die Informationen darüber abrufen, wie viele Objekte zugewiesen werden müssen (hier sind es 100), und ruft den Konstruktor für jedes der erstellten Objekte auf

Wenn wir dies jedoch nur delete ptrfür diesen Fall verwenden, weiß der Compiler nicht, auf wie viele Objekte er ptrverweist, und ruft am Ende den Destruktor auf und löscht den Speicher für nur ein Objekt (wobei der Aufruf von Destruktoren und die Freigabe der verbleibenden 99 Objekte verbleiben). Daher kommt es zu einem Speicherverlust.

also müssen wir delete [] ptrin diesem Fall verwenden.

ravs2627
quelle
3
Dies sollte die richtige Antwort sein. Keine der anderen Antworten erwähnt den deutlichen Unterschied: "Wenn wir jedoch in diesem Fall einfach delete ptr verwenden, weiß der Compiler nicht, auf wie viele Objekte ptr zeigt, und ruft am Ende den Destruktor auf und löscht den Speicher für nur 1 Objekt."
Don Larynx
1
Wie erreichen wir dasselbe in C?
Dogus Ural
@ DogUUral Warum? Es gibt keine Destruktoren in C, also nur free()dies und das. Wenn Sie ein Pseudo-Destruktor-Muster verwenden, müssen Sie es für jedes Objekt mithilfe einer forSchleife einmal aufrufen .
Kotauskas
@DonLarynx Der richtige Unterschied ist, dass das Verwechseln zu einem schlecht geformten Programm führt. Eine Implementierung weiß möglicherweise , wie viele Objekte zerstört werden sollen, oder nicht . Es ist zulässig zu wissen, dass es als falsch bezeichnet wurde, und das Programm abzubrechen, um Ihnen mitzuteilen, wo das Problem liegt.
Caleth
6

Die Operatoren deleteund delete []werden jeweils verwendet, um die mit newund erstellten Objekte zu zerstören und new[]zu dem zugewiesenen Speicher zurückzukehren, der dem Speichermanager des Compilers zur Verfügung steht.

Mit erstellte Objekte newmüssen unbedingt mit zerstört werden delete, und die mit erstellten Arrays new[]sollten mit gelöscht werden delete[].

san983
quelle
2

Als ich diese Frage stellte, war meine eigentliche Frage: "Gibt es einen Unterschied zwischen den beiden? Muss die Laufzeit nicht Informationen über die Arraygröße behalten, und kann sie dann nicht sagen, welche wir meinen?" Diese Frage erscheint nicht in "verwandten Fragen". Um nur Leuten wie mir zu helfen, hier die Antwort darauf: "Warum brauchen wir überhaupt den Operator delete []?"

Ekalavya
quelle
Vielen Dank, dass Sie zurückgekommen sind und dies
eingegeben haben
0

deletewird für einen einzelnen Zeiger verwendet und delete[]zum Löschen eines Arrays über einen Zeiger. Dies könnte Ihnen helfen, besser zu verstehen.

nishant arora
quelle
-6

Naja .. vielleicht denke ich es ist nur explizit. Der Operator deleteund der Operator delete[]werden unterschieden, aber der deleteOperator kann auch das Array freigeben.

test* a = new test[100];
delete a;

Und bereits überprüft, hat dieser Code kein Speicherleck.

Hallo Welt
quelle