wake-up-neo.net

Warum setzt delete den Zeiger nicht auf NULL?

Ich habe mich immer gefragt, warum das automatische Setzen des Zeigers auf NULL nach Löschen nicht zum Standard gehört. Wenn dies behoben wird, treten viele Abstürze aufgrund eines ungültigen Zeigers nicht auf. Allerdings kann ich mir einige Gründe vorstellen, warum der Standard dies eingeschränkt hätte:

  1. Performance:

    Eine zusätzliche Anweisung kann die Leistung von delete verlangsamen.

  2. Könnte es an const Zeigern liegen.

    Andererseits hätte Standard etwas für diesen speziellen Fall tun können, denke ich.

Kennt jemand genaue Gründe, warum man das nicht zulässt?

119
aJ.

Stroustrup selbst antwortet. Ein Ausschnitt:

C++ erlaubt explizit eine Implementierung von delete, um einen lvalue-Operanden auf Null zu setzen, und ich hatte gehofft, dass Implementierungen dies tun würden, aber diese Idee scheint bei Implementierern nicht populär geworden zu sein.

Das Hauptproblem, das er aufwirft, ist jedoch, dass das Argument von delete kein Wert sein muss.

146
Dan Olson

Erstens würde das Setzen auf Null eine gespeicherte Speichervariable erfordern. Es ist wahr, dass Sie normalerweise einen Zeiger in einer Variablen haben, aber manchmal möchten Sie vielleicht löschen ein Objekt an einer gerade berechneten Adresse. Das wäre unmöglich mit "annullieren" löschen.

Dann kommt die Leistung. Möglicherweise haben Sie Code so geschrieben, dass der Zeiger den Gültigkeitsbereich sofort verlässt, nachdem delete ausgeführt wurde. Es mit null zu füllen ist nur Zeitverschwendung. Und C++ ist eine Sprache mit der Ideologie "Brauchst du es nicht? Dann musst du nicht dafür bezahlen".

Wenn Sie Sicherheit brauchen, gibt es eine große Auswahl an nützlichen Hinweisen, oder Sie können Ihre eigenen schreiben - besser und intelligenter.

60
sharptooth

Sie können mehrere Zeiger auf diesen Speicher haben. Es würde ein falsches Sicherheitsgefühl erzeugen, wenn der von Ihnen für das Löschen angegebene Zeiger auf null gesetzt würde, alle anderen Zeiger jedoch nicht. Ein Zeiger ist nichts weiter als eine Adresse, eine Zahl. Es könnte genauso gut ein int mit einer Dereferenzierungsoperation sein. Mein Punkt ist, dass Sie auch jeden einzelnen Zeiger scannen müssen, um diejenigen zu finden, die auf denselben Speicher verweisen, den Sie gerade gelöscht haben, und sie auch auf Null zu setzen. Es wäre rechenintensiv, alle Zeiger nach dieser Adresse abzusuchen und sie auf Null zu setzen, da die Sprache nicht dafür ausgelegt ist. (Obwohl einige andere Sprachen ihre Referenzen strukturieren, um ein ähnliches Ziel auf andere Weise zu erreichen.)

36
AaronLS

Ein Zeiger kann in mehr als einer Variablen gespeichert werden. Wenn Sie einen dieser Zeiger auf NULL setzen, bleiben in den anderen Variablen weiterhin ungültige Zeiger. Sie gewinnen also nicht wirklich viel, sondern schaffen mit größerer Wahrscheinlichkeit ein falsches Sicherheitsgefühl.

Außerdem können Sie Ihre eigene Funktion erstellen, die das tut, was Sie wollen:

template<typename T>
void deleten(T *&ptr) {
  delete ptr;
  ptr = NULL;
}
18
sth

Da dies nicht wirklich erforderlich ist und das Löschen von Zeigern anstelle von Zeigern erforderlich ist.

12
snemarch

delete wird hauptsächlich in Destruktoren verwendet. In diesem Fall ist es sinnlos, ein Member auf NULL zu setzen. Ein paar Zeilen später, am Schluss }, das Mitglied existiert nicht mehr. In Zuweisungsoperatoren folgt auf ein Löschen ohnehin in der Regel eine Zuweisung.

Außerdem würde der folgende Code illegal:

T* const foo = new T;
delete foo;
7
MSalters

Hier ist ein weiterer Grund; Angenommen, delete setzt sein Argument auf NULL:

int *foo = new int;
int *bar = foo;
delete foo;

Soll bar auf NULL gesetzt werden? Können Sie das verallgemeinern?

Wenn Sie ein Array mit Zeigern haben und als zweite Aktion das leere Array löschen möchten, gibt es keinen Punkt, der jeden Wert auf Null setzt, wenn der Speicher freigegeben werden soll. Wenn Sie wollen, dass es null ist, schreiben Sie null darauf :)

5
Dead account

Mit C++ können Sie Ihren eigenen Operator neu definieren und löschen, sodass er beispielsweise Ihren eigenen Pool-Allokator verwendet. Wenn Sie dies tun, ist es möglich, new und delete mit Dingen zu verwenden, bei denen es sich nicht um reine Adressen handelt, sondern um Indizes in Ihrem Pool-Array. In diesem Zusammenhang kann der Wert von NULL (0) eine rechtliche Bedeutung haben (in Bezug auf das erste Element im Pool).
Wenn delete also NULL automatisch auf sein Argument setzt, hat dies nicht immer die Bedeutung von - Setzen Sie den Wert auf einen ungültigen Wert. Der ungültige Wert ist möglicherweise nicht immer NULL.

4
shoosh

Die Philosophie von C++ lautet: "Zahlen Sie nur, wenn Sie es verwenden". Ich denke, es könnte Ihre Frage beantworten.

Manchmal können Sie auch einen eigenen Heap haben, der den gelöschten Speicher wiederherstellt. Manchmal gehört der Zeiger keiner Variablen. Oder Zeiger in wenigen Variablen gespeichert - es ist möglich, nur einen von ihnen auf Null zu setzen.
Wie Sie sehen, gibt es viele Probleme und mögliche Probleme.

4
bayda

Das automatische Setzen des Zeigers auf NULL würde die meisten Probleme mit einer schlechten Zeigerverwendung nicht lösen. Der einzige Absturz, den es vermeiden würde, ist, wenn Sie versuchen, es zweimal zu löschen. Was ist, wenn Sie eine Member-Funktion für einen solchen Zeiger aufrufen? Es würde immer noch abstürzen (vorausgesetzt, es greift auf Mitgliedsvariablen zu). C++ hindert Sie weder daran, Funktionen für NULL-Zeiger aufzurufen, noch sollte es dies unter Performance-Gesichtspunkten tun.

3
Vega