2016-07-12 20 views
0

Ich habe Thema gelesen Calling delete on variable allocated on the stack Und ich weiß, wenn Benutzer im Stapel löschen, siehe Fehler. Aber ich möchte mehr und tiefere Informationen wissen. Warum Fehler?Warum Zeiger auf Stapel löschen ist ein Fehler?

+0

müssen Sie wissen, was zuerst Stapel ist. Wenn Sie Speicher im Stack löschen, wird Ihr Stack nicht mehr zusammenhängend sein, aber die Laufzeit hängt von dieser Tatsache ab. – Incomputable

+0

Anders ist nicht das Gleiche. - Fred Picker –

+2

Sie löschen keinen Zeiger, den Sie nicht "neu" gemacht haben. Es gibt nichts tiefer als das, es ist nur was die Regeln der Sprache sind. – dxiv

Antwort

1

Stapel erstellten Objekte sind automatische während nicht-Stack erzeugten Objekte (mit dem Schlüsselwort new) sind dynamische und müssen das Schlüsselwort delete aufgearbeiteten werden.

Objekte auf dem Stapel werden durch das System automatisch einen aufgearbeiteten anderen Mechanismus auf Objekte dynamisch Schlüsselwort zugeordnet Verwendung new.

So Stichwort Aufruf delete mit einer Objektadresse, der nicht dynamisch mit dem Schlüsselwort new verursachen Probleme gebunden zugeordnet wurde.

1

Begraben (nicht sehr tief) in den C++ - Laufzeitbibliotheken ist eine Datenstruktur, die als Heap bezeichnet wird. Der Heap-Job (konzeptionell sowieso) besteht darin, mit einem riesigen Array von Bytes zu beginnen und Teile dieses Arrays zu Ihrem Programm zu übertragen, wenn Ihr Programm danach fragt. Auf diese Weise müssen Sie selbst keinen Chunk-Management-Code implementieren (was gut ist, weil die korrekte und effiziente Handhabung in allen Fällen eine nicht-triviale Codierungsaufgabe ist).

Immer wenn Ihr Programm den Operator new aufruft, trennt ein Aufruf des Heap-Codes einen Teil dieses Arrays (ebenfalls konzeptionell) und übergibt es an Ihr Programm. Umgekehrt, wenn Sie später den Operator delete aufrufen, wird dieses Sub-Array von Bytes an den Heap zurückgegeben, wobei der Code des Heaps es wieder zusammen mit seinen benachbarten Abschnitten eines großen Arrays zusammenführen kann (wenn einer oder beide der benachbarten Abschnitte auch sind) verfügbar sein) oder zumindest die Verfügbarkeit aufzeichnen, damit sie später über einen nachfolgenden Aufruf an new wieder verwendet werden kann.

Objekte auf dem Stapel befinden sich jedoch nicht innerhalb des riesigen Arrays des Heaps; Sie befinden sich vielmehr auf dem Stapel. Wenn Sie also delete für ein Stack-Objekt aufrufen, übergeben Sie dem Heap ein Speicherstück, das nie Teil seines Ressourcen-Pools war. Die C++ - Sprachdesigner hätten verlangen können, dass jede Heap-Implementierung nach dieser Bedingung sucht und eine vorhersehbare Reaktion ausführt (z. B. einfach den unbekannten Zeiger ignoriert oder eine Fehlermeldung ausgibt oder einen Assertionsfehler auslöst und das Programm beendet), aber dies tut Ein solcher Check für jede delete könnte ineffizient sein, und die C++ - Sprache priorisiert die Dinge so effizient wie möglich zur Laufzeit. Daher wird durch die Übergabe eines Zeigers an delete, der zuvor nicht von new zurückgegeben wurde, undefined Verhalten, was bedeutet, dass der Designer der C++ - Laufzeitbibliothek nicht kümmern muss, was sein Heap-Code in dieser Situation tun wird, da diese Situation nie passieren in erster Linie - es wird nur passieren, wenn Sie einen Programmierfehler gemacht haben. Also, machen Sie diesen Fehler nicht, weil es Ihr Programm dazu bringt, sich so zu verhalten, wie Sie es nicht wollten.

0

Um es richtig zu verstehen, sollten Sie zuerst verstehen, was Stapel ist und was Haufen bedeuten. Gehen Sie durch this, um zu verstehen, wie Prozessspeicher ausgerichtet ist.

Wenn Sie eine Funktion aufrufen, empfängt sie zusammenhängende Speicherblöcke aus dem virtuellen Kern des Prozesses. die es verwendet, um Argumente zu empfangen, lokale Variablen zu definieren und Absenderadresse usw. zu speichern. Dieser Speicher wird freigegeben, sobald die Funktion ihre Ausführung beendet und zurückkehrt. Dies nennt man Stapel.

Wo die Heap-Zuweisung zur Laufzeit erfolgt. und daher ist es nicht garantiert, dass sie zusammenhängend sind. new Funktionsaufruf findet geeigneten Speicherblock für Sie aus dem freien Pool und löscht es zurück in den freien Speicherpool.

Da Stack und Heap physikalisch unterschiedliche Entitäten sind, sollten auf Heap definierte Operationen nicht auf dem Stack ausgeführt werden, da dies zur Laufzeit undefiniertes Verhalten zur Folge hat, wie von Jeremy Friesner erläutert. Als Faustregel ist es besser, Fehler so früh wie möglich zu melden, und genau das tut der Compiler, wenn er ein gefundenes Objekt findet, das auf dem Stapel definiert wurde.

+0

Ein hilfreicher Compiler kann den Fehler melden, aber es ist nicht erforderlich, damit Sie sich nicht darauf verlassen können. –