it-swarm.com.de

C++ einen Zeiger löschen (freier Speicher)

Betrachten Sie den folgenden Code:

int a = 10;
int * b = &a;
int * c = b;
delete b; // equivalent to delete c;

Verstehe ich es in der letzten Zeile richtig zu verstehen, dass delete b und delete c gleichwertig sind und dass beide den Speicherplatz freigeben, der a hält, so dass a nicht mehr erreichbar ist?

11
space_voyager

Das Verhalten Ihres Programms ist undefined. Sie können nurdelete für einen Zeiger auf den Speicher verwenden, den Sie mit new zugewiesen haben. Wenn du geschrieben hättest 

int* b = new int;
*b = 10;
int* c = b;

dann können Sie könnte schreiben entwederdelete b;oderdelete c;, um Speicherplatz freizugeben. Versuchen Sie nicht, derefererence entweder b oder c nach dem Aufruf von delete zu starten. Das Verhalten bei der Ausführung ist jedoch auch (undefined.

42
Bathsheba

Wenn b und c auf den gleichen Speicher zeigen, wird durch Löschen einer der beiden der Speicher freigegeben, so dass die Annahme richtig ist. Die a-Unzugänglichkeit ist in diesem Fall nicht korrekt, da Sie nicht auf dynamisch zugewiesenen Speicher zeigen und delete/delete[] nur für etwas aufrufen können, das mit new/new[] erstellt wurde. Der Versuch, einen delete/delete[] zu versuchen, einen Zeiger, der nicht mit new/new[] zugewiesen wurde, ist ein undefiniertes Verhalten und endet im Allgemeinen mit einem Segmentierungsfehler.

5
NathanOliver

Der verwirrende Teil ist die Antwort auf Ihre Frage

Bin ich in der letzten Zeile richtig zu verstehen, löschen b und c löschen sind gleichwertig "

Ist ja, sie sind gleichwertig und beide UB wie überall sonst erwähnt.

5
UKMonkey

Diese spezielle Antwort verwendet eine bestimmte Implementierung des Heap, um detailliert zu beschreiben, was in Ihrer vorgeschlagenen Situation passieren würde. Dies ist jedoch sehr unwichtig, da andere Versionen in der Nähe meines Arguments immer noch ähnliche Probleme hätten.

Die Antwort lautet "Nein", und das liegt an dem, was andere Leute gesagt haben. Ich werde jedoch etwas genauer sein, weil ich glaube, dass Sie nicht wirklich wissen, was Stapel und Haufen sind, und dass ich mir die Zeit nehme, Ihnen das zu erklären.

Zunächst einmal ist alles, was ich in Bezug auf Details über den Haufen sage, eine "Lüge". Niemand weiß genau, was Ihr Compiler tut, um den Heap zu implementieren. Also kann ich nur mein Verständnis von a Haufen vermitteln.

Neu und Löschen sind eigentlich zwei Funktionen (wenn Sie von einer Überladung des Operators gehört haben, werden Sie verstehen, was ich damit meine), die Zeiger akzeptiert und eine als Heap bezeichnete Datenstruktur im Speicher ändert. Es ist eine von vier Hauptdatenstrukturen im Speicher eines C/C++ - Programms (der Heap, der Stack, der Text und der statische Raum).

Der Heap ist im Wesentlichen eine verknüpfte Liste, aber anstatt Daten in jedem Knoten zu speichern, stoppt man die Daten dazwischen. Wenn Sie mit einer verknüpften Liste nicht vertraut sind, handelt es sich in diesem Zusammenhang um ein zweikomponentiges "Array", das sich im Rohspeicher befindet. Die zweite Komponente ist die Länge des davor gespeicherten Blocks. Die erste Komponente ist die Länge des Blocks vor ihm. Auf diese Weise ist es einfach, einen Block zu finden, da es nur darum geht, in der Liste nach einem Block zu suchen. Normalerweise (da Programme nicht annähernd komplex genug sind, um 2 ^ 31 Bytes innerhalb eines einzelnen Blocks zuzuordnen), wird das Bit ganz links als True/False-Wert verwendet, der angibt, ob der Block frei ist. Frei und neu sind also nur Operationen auf der Liste, und free sichert einfach den Zeiger um eins, um den Knoten zu betrachten und entsprechende Änderungen vorzunehmen. Ich werde nicht weiter ins Detail gehen, weil diejenigen, die mit doppelt verknüpften Listen vertraut sind, die Operationen verstehen sollten. Wenn Sie dies nicht verstehen, ist es sinnlos, wenn ich Ihnen etwas beibringen möchte, das Sie später in viel größerer Tiefe lernen werden.

Denken Sie daran: Ihre Implementierungen variieren je nach Compiler. Dies ist nur ein Beispiel.

Auf der anderen Seite befinden sich die lokalen Variablen. Es ist buchstäblich eine riesige Reihe von Arrays. Die Mitte des Arrays enthält die Adresse im Code, zu der das Programm nach der Ausführung zurückkehren soll, und dann befinden sich die Parameter auf der einen Seite, während sich die lokalen Variablen auf der anderen befinden. Die lokalen Variablen haben kein klares Organisationsgefühl. Einige Compiler stellen möglicherweise fest, dass ein Wert nicht mehr vor einem anderen verwendet wird, sondern teilen sich nur den Speicherort (Sie würden es nie bemerken, es sei denn, Sie haben tatsächlich in den Speicher geguckt oder den Stapel gescannt).

Wie Sie sehen können, machen die beiden einfach keinen Sinn. Das Aufrufen eines Zeigers, der den Stapel indiziert, bedeutet, dass Sie versuchen, die Listenoperation auf dem Stapel auszuführen. Eines von zwei Dingen wird passieren:

  1. Ihre Implementierung erkennt, dass sich der Speicher nicht einmal im Heap befindet, und wird mit einer Fehlermeldung angezeigt (Ausnahme für illegale Argumente).

  2. Die Implementierung ist "dumm" und versucht tatsächlich, die Listenoperation auszuführen. Dies bedeutet, dass der Wert vor der Variablen im Speicher geändert wird und andere Werte möglicherweise geändert werden, um zu versuchen, zwei freie Blöcke in einen größeren Block zu "mischen".

Einfach gesagt: Tu das nicht. Sie könnten in Ihrem Programm etwas kaputt machen. Was ist, wenn Sie die Rückleitung versaut haben? Als nächstes haben Sie eine unendliche Schleife von Funktionsaufrufen, aber Sie haben keine Schleifen geschrieben. Sehr sehr schlecht.

Und natürlich:

Ihre genaue Implementierung des Heaps variiert stark, im Gegensatz zu dem Stapel, der sich nicht viel ändert.

Während ich zum Beispiel den Code oder ein Diagramm des Rohspeichers einer solchen Struktur noch nie gesehen habe, habe ich gehört, dass Modelle für den Heap-Speicher in der Umgebung vorhanden sind. Es gibt zwei separate Listen, die die freigegebenen Blöcke und die zugewiesenen Blöcke enthalten. Dies hätte jedoch keine Auswirkungen auf die Frage, da es immer noch eine Form der internen Buchhaltung gibt, die sich mit der Zuordnung befasst.

0
The Great Duck

sie sollten delete niemals für Variablen verwenden, die auf dem Stack zugewiesen sind. delete ist das Gegenstück von new . Daher ist kein delete/free erforderlich, wenn kein new/attach verwendet wird, wenn Sie sich außerhalb des "Bereichs" befinden Für den Code (in diesem Fall das Programm selbst) wird der gesamte Speicher als verfügbar betrachtet.

0
Nir Levy