2009-04-01 1 views
108

Ich habe mich immer gewundert, warum automatische Einstellung des Zeigers auf Null nach löschen ist nicht Teil des Standards. Wenn dies erledigt wird, dann würden viele der Abstürze aufgrund eines ungültigen Zeigers nicht auftreten. Aber gesagt haben, dass ich aus mehreren Gründen denken kann, warum der Standard dies eingeschränkt haben würde:Warum löscht nicht den Zeiger auf NULL setzen?

  1. Performance:

    Eine zusätzliche Anweisung, die delete Leistung verlangsamen könnte.

  2. Konnte es wegen const Zeigern sein.

    Dann hätte wieder Standard für diesen speziellen Fall etwas getan, denke ich.

Kennt jemand genauen Gründe für diese nicht erlaubt?

Antwort

138

Stroustrup himself Antworten. Ein Auszug:

C++ erlaubt explizit eine Implementierung der Lösch- einen L-Wert-Operanden auf Null, und ich hatte gehofft, dass Implementierungen würde das tun, aber diese Idee nicht populär zu haben scheint mit Implementierer.

Aber das Hauptproblem, das er aufwirft, ist, dass das Argument von delete kein lvalue sein muss.

12

Weil es nicht wirklich notwendig ist, und weil es würde Delete erfordern Pointer-to-Pointer und nicht nur Zeiger.

+1

Oder Verweis auf Zeiger. –

+0

true, aber das würde in der gleichen Overhead – snemarch

5

Wenn Sie ein Array von Zeigern haben und Ihre zweite Aktion das leere Array löschen soll, dann gibt es keinen Grund, jeden Wert auf null zu setzen, wenn der Speicher freigegeben wird. Wenn Sie möchten, dass es null ist .. schreiben Sie Null auf es :)

54

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

Dann kommt die Leistung. Möglicherweise haben Sie den Code so geschrieben, dass der Zeiger sofort nach delete gelöscht wird. Es mit Null zu füllen ist nur eine Zeitverschwendung. Und C++ ist eine Sprache mit "brauchen Sie es nicht? Dann müssen Sie nicht dafür bezahlen" Ideologie.

Wenn Sie Sicherheit brauchen, gibt es eine große Auswahl an intelligenten Zeigern, die Sie bedienen können, oder Sie können Ihre eigenen schreiben - besser und intelligenter.

+4

Guter Punkt wrt berechnete Adresse, auch wenn es etwas ist, was Sie nicht oft sehen – snemarch

+0

sprechen Sie über Placement neu, wenn Sie sagen, dass Sie manchmal ein Objekt zu einem gerade löschen möchten berechnete Adresse. ??? – Destructor

+0

@PravasiMeet Nein, ich meine etwas wie 'delete (ptr + i)' – sharptooth

35

Sie können mehrere Zeiger auf diesen Speicher haben. Es würde ein falsches Gefühl der Sicherheit erzeugen, wenn der Zeiger, den Sie für das Löschen angegeben haben, auf null gesetzt wurde, aber alle anderen Zeiger nicht. Ein Zeiger ist nichts weiter als eine Adresse, eine Zahl. Es könnte auch ein Int mit einer Dereferenzierungsoperation sein. Mein Punkt ist, dass Sie auch jeden einzelnen Zeiger durchsuchen müssen, um diejenigen zu finden, die auf den gleichen Speicher verweisen, den Sie gerade gelöscht haben, und sie auch ausnutzen. Es wäre rechenintensiv, alle Zeiger auf diese Adresse zu scannen und sie auf Null zu setzen, weil die Sprache dafür nicht ausgelegt ist. (Obwohl einige andere Sprachen ihre Referenzen strukturieren, um ein ähnliches Ziel anders zu erreichen.)

17

Ein Zeiger kann in mehr als einer Variablen gespeichert werden. Wenn Sie eine dieser Variablen auf NULL setzen, bleiben ungültige Zeiger in den anderen Variablen. Sie gewinnen also nicht wirklich viel, Sie erzeugen wahrscheinlicher ein falsches Sicherheitsgefühl.

Abgesehen davon, können Sie Ihre eigene Funktion erstellen, das tut, was Sie wollen:

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

C++ können Sie Ihre eigenen Bediener neu definieren und löschen, so dass zum Beispiel würden sie Ihren eigenen Pool Allocator verwenden. Wenn Sie dies tun, ist es möglich, new zu verwenden und mit Dingen zu löschen, die keine strikten Adressen sind, sondern Indizes in Ihrem Pool-Array. In diesem Kontext hat der Wert von NULL (0) möglicherweise eine rechtliche Bedeutung (bezogen auf den ersten Eintrag im Pool).
Wenn also delete NULL automatisch auf sein Argument gesetzt hat, hat das nicht immer die Bedeutung von - setze den Wert auf einen ungültigen Wert. Der ungültige Wert ist möglicherweise nicht immer NULL.

3

Das automatische Setzen des Zeigers auf NULL würde die meisten Probleme mit schlechter 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 Memberfunktion für einen solchen Zeiger aufrufen? Es würde immer noch abstürzen (unter der Annahme, dass es auf Member-Variablen zugreift). C++ beschränkt Sie nicht darauf, irgendeine Funktion auf NULL-Zeigern aufzurufen, noch sollte dies aus Sicht der Leistung geschehen.

4

Philosophie von C++ ist "nur dafür bezahlen, wenn Sie es verwenden". Ich denke, dass es deine Frage beantworten kann.

Auch manchmal könnten Sie Ihren eigenen Heap haben, der gelöschten Speicher wiederherstellen wird .. oder manchmal Zeiger, der keiner Variablen gehört. Oder Zeiger in wenigen Variablen gespeichert - es ist möglich, nur eine von ihnen null.
Wie Sie sehen können, gibt es viele Probleme und mögliche Probleme.

7

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 }, existiert das Mitglied nicht mehr. In Zuweisungsoperatoren folgt auf eine Löschung in der Regel eine Zuweisung.

Auch wäre es den folgenden Code machen illegal:

T* const foo = new T; 
delete foo; 
4

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

Sollte bar auf NULL gesetzt werden? Kannst du das verallgemeinern?

-2

Ich sehe Menschen, die auf diese Frage seltsame Antworten geben.

ptr = NULL; Wie kann solch eine einfache Aussage Leistungsverzögerung verursachen?

Eine andere Antwort besagt, dass wir mehrere Zeiger auf denselben Speicherort haben können. Sicher können wir es.In diesem Fall würde die Löschoperation für einen Zeiger nur diesen Zeiger NULL machen (wenn delete Zeiger NULL macht) und der andere Zeiger wäre nicht NULL und zeigt auf Speicherstelle, die frei ist.

Die Lösung für diese sollte sein, dass Benutzer alle Zeiger löschen sollte, die auf denselben Speicherort verweisen. Intern sollte überprüft werden, ob der Speicher bereits frei ist. Machen Sie den Zeiger nur NULL.

Stroustrup könnte gelöscht haben, um auf diese Weise zu arbeiten. Er dachte, Programmierer würden sich darum kümmern. Also ignorierte er.