Findet ihr es gut das delete bei Null-Pointern definiertes Verhalten hat?



  • In meinen Klassen gibt es Arrays, die nur gelegentlich bereit stehen müssen. den Rest der Zeit über lösche ich sie und setze ihre Zeiger auf 0. Jetz muss ich beim Destruktor nicht nur nicht auf 0 prüfen, sondern kann auch anhand des Array-Zeigers selbst überprüfen, ob das Array bereits existiert. Also in meinen Fällen nutze ich das definierte Verhalten von delete bei 0 direkt aus; nur um mal ein Beispiel zu nennen, wo Null-Zeiger KEINE Fehler sein können.



  • Sir Gossi schrieb:

    [...]nur um mal ein Beispiel zu nennen, wo Null-Zeiger KEINE Fehler sein können.

    Wurde das irgendwo behauptet?



  • Was mir gerade einfällt -> Wenn man ein Objekt löscht indem man delete zeigeraufsobjekt macht, wäre es dann nicht auch möglich das der Zeiger dann auf die Speicheradresse 0000 zeigt? Und das dann wenn man am Ende wie Michael E. alle Pointer nochmal deleted ein schwer zu findender Fehler auftritt?



  • @MaSTaH

    Ponto schrieb:

    In fast allen Fällen, die mir unterkommen, ist ein Pointer mit dem Wert 0 beim delete ein Hinweis auf einen Fehler in meiner Logik.



  • Delryn schrieb:

    Was mir gerade einfällt -> Wenn man ein Objekt löscht indem man delete zeigeraufsobjekt macht, wäre es dann nicht auch möglich das der Zeiger dann auf die Speicheradresse 0000 zeigt? Und das dann wenn man am Ende wie Michael E. alle Pointer nochmal deleted ein schwer zu findender Fehler auftritt?

    Nein, das ist nicht möglich. Diese Speicheradresse wird nie vergeben, wenn es sie überhaupt gibt.



  • Sir Gossi schrieb:

    @MaSTaH

    Ponto schrieb:

    In fast allen Fällen, die mir unterkommen, ist ein Pointer mit dem Wert 0 beim delete ein Hinweis auf einen Fehler in meiner Logik.

    Ich meinte meine Logik, bei anderen Programmierstilen kann das natürlich anders sein.

    Tatsächlich verwende ich direkt per new allozierte Objekte so selten wie möglich und damit auch selten Zeiger. Dynamisch allozierte Objekte werden besser mit std::vector oder anderen Container verwaltet, so dass ein new/delete direkt im Code zu einer Rarität geworden ist.

    Wenn ich dann doch mal mit new/delete Arbeite gibt es immer einen Manager, der dafür zuständig ist, damit sich der eigentliche Code nicht mit so etwas herumschlagen muss. Bei denen ist es meistens so, dass wenn sie auf einen 0 Zeiger treffen, etwas nicht in Ordnung ist.



  • @Sir Gossi: Du hattest aber etwas anderes gesagt. Du hast ein Beispiel dafür gebracht, wo Nullpointer keine Fehler sein können, das hatte aber niemand bestritten. Es wurde ja nur gesagt, dass ein delete auf selbige ein Anzeichen für fehlerhaften Code sein kann.



  • Sir Gossi schrieb:

    Delryn schrieb:

    Was mir gerade einfällt -> Wenn man ein Objekt löscht indem man delete zeigeraufsobjekt macht, wäre es dann nicht auch möglich das der Zeiger dann auf die Speicheradresse 0000 zeigt? Und das dann wenn man am Ende wie Michael E. alle Pointer nochmal deleted ein schwer zu findender Fehler auftritt?

    Nein, das ist nicht möglich. Diese Speicheradresse wird nie vergeben, wenn es sie überhaupt gibt.

    Afaik gibts die Speicheradresse 0000, z.B. im rom wo der erste Befehl drinne steht denn sich die cpu holt.



  • Wobei das wieder von der Plattform abhängig ist...



  • Oft hat man aber irgendeinen Zeiger und setzt ihn im Constructor auf 0. Irgendwann später dann wird vielleicht was alloziert und in diesem Pointer gespeichert oder auch nicht. Im destructor schreibt man dann einfach delete, und alles funktioniert so wie es soll.



  • Sir Gossi schrieb:

    In meinen Klassen gibt es Arrays, die nur gelegentlich bereit stehen müssen.

    Dann nimm ein scoped_array, einen vector o.ä. Alles, was mit rohen Zeigern zu tun hat, hat eh schon mehr als genug implizite "Features" - da wäre es mir lieber, sie wären umständlicher (und damit klarer) zu bedienen, weil sie eh gewrappt werden sollten. D.h. klares Ja zur manuellen Null-Abfrage, da sie eh nur in Destruktoren von Wrapperklassen vorkommt.



  • Ach, ich hatte bisher keine Probleme mit meinen temporären Arrays.

    @Delryn: Das mit der Speicheradresse 0000 hat man mir das letzte mal als ich in diesem Forum danach gefragt hab aber noch anders beigebracht.



  • Delryn schrieb:

    Afaik gibts die Speicheradresse 0000, z.B. im rom wo der erste Befehl drinne steht denn sich die cpu holt.

    Natürlich gibts die Adresse. Aber 1) zeigt der Nullpointer nicht zwingend auf die Adresse 0. Das heißt, wenn du z.B. ptr=0 schreibst, ersetzt der Compiler die 0 intern durch die "richtige" Nullpointer-Adresse, so dass du dich in der Praxis nicht mit dieser Umsetzung herumschlagen musst.
    Und 2) heißt es ja nur, dass kein gültiger Zeiger je ein Nullpointer ist. Also wenn dort irgendwelcher ROM-Code steht, passt das doch perfekt, weil weder ein Objekt noch eine Funktion an dieser Stelle stehen kann.



  • liver schrieb:

    Findet ihr das gut? Das versteckt doch nur einen Logikfehler oder nicht? hmm

    es ist voll kacke.
    es untergräbt fast alles, woran ich glaube.
    es versteckt logikfehler. ein assert oder irgend was anderes hartes wäre da im debug-modus angebracht. im release-modes schlich undefiniert. (üblicherweise sehr schnell oder sofort schutzverletzung).
    es ist lahm. ok, nur wenige takte pro delete, aber wenige absolut und vollkommen unnütze takte.



  • Das mit der Geschwindigkeit stimmt, aber new/delete sind von Haus aus sehr langsam (tausende Takte), da fällt das wirklich nicht ins Gewicht.



  • Das hängt doch vom Allokator ab.



  • volkard schrieb:

    liver schrieb:

    Findet ihr das gut? Das versteckt doch nur einen Logikfehler oder nicht? hmm

    es ist voll kacke.

    Ich find's gut, denn ein Nullpointer ist ein schöner Sentinel-Wert den ich recht häufig und gerne verwende. Das man sich explizite if-Abfragen beim Löschen von z.B. optionalen Aggregationen sparen kann macht Code imo einfacher und leichter zu verstehen (anderes Beispiel: Implementation von Move-Operationen). Logikfehler wurden bei mir durch dieses Verhalten bisher nicht versteckt, da ein Nullpointer ja nicht zufällig entsteht. Entweder der Nullpointer hat eine von mir definierte Semantik, dann setze ich Pointer explizit auf 0 (auch mal nach einem delete) und erlaube damit gerne auch mehrfache Aufrufe von delete oder aber, wenn es keine definierte Semantik gibt, setze ich Pointer nicht auf 0 und damit haut's einen bei z.B. Doppel-Deletes schnell raus und Logikfehler werden imo auch nur mit einer äußersts geringen Wahrscheinlichkeit verschleiert.
    Wenn ich auf der anderen Seite Code habe, der von der Annahme ausgeht, dass ein Pointer nicht 0 sein kann (oder darf), dann stelle ich dies über ein explizites Assert sicher. Das hat den Vorteil, dass es a) deutlicher sichtbar ist (nicht versteckt in der Implementation eines Implementationsdetails) und b) den Fehler potentiell früher finden kann (nicht erst beim Löschen).

    Was ich nicht mache und was ich in der Tat für schlecht halte ist die generelle Verwendung von Code wie diesem:

    delete p;
    p = 0;
    

    Mit der Begründung "ich will mich vor Doppel-Deletes" schützen. Das führt dann häufig wirklich zur Verschleierung von Logikfehlern.

    Aber letztlich ist das konkrete Verhalten von delete eh wurscht, solange es explizit und vollständig spezifiziert ist. Wie man hier sieht kann man es eh nie allen Recht machen.



  • Findet ihr es gut das delete bei Null-Pointern definiertes Verhalten hat?

    Ja.

    Findet ihr das gut?

    Ja. 😕

    Das versteckt doch nur einen Logikfehler oder nicht?

    Nein.



  • [quote="HumeSikkins"]Ich find's gut, denn ein Nullpointer ist ein schöner Sentinel-Wert den ich recht häufig und gerne verwende. [quote]
    das ist bedeutungsüberladung.

    Das man sich explizite if-Abfragen beim Löschen von z.B. optionalen Aggregationen sparen kann macht Code imo einfacher und leichter zu verstehen (anderes Beispiel: Implementation von Move-Operationen).

    ich frage gerne der deutlichkeit habler dennoch und überflüssigerweise mit if ab.

    Was ich nicht mache und was ich in der Tat für schlecht halte ist die generelle Verwendung von Code wie diesem:

    delete p;
    p = 0;
    

    Mit der Begründung "ich will mich vor Doppel-Deletes" schützen. Das führt dann häufig wirklich zur Verschleierung von Logikfehlern.

    stimmt.
    aber man baut sich dann ja eh ein void sicherLoesch(T*& t);

    Aber letztlich ist das konkrete Verhalten von delete eh wurscht, solange es explizit und vollständig spezifiziert ist. Wie man hier sieht kann man es eh nie allen Recht machen.

    naja, ich mag halt zero abstraction overhead. mag nicht sachen eingebaut haben, nur weil man es manchmal braucht.
    viele zeiger sind bei mir attribute und sie zeigen sicher auf was (vom ctor sichergestellt).

    es wäre kein problem, wenn delete minimal wäre, also bei delete 0; undefiniert wäre, sich einen smart-pointer zu bauen, der die semantik hat, daß man nen null-zeiger fehlerfrei löschen darf. damit könnte man es beiden seiten recht machen. aber so, wie es jetzt ist, bin ich nicht ganz zufrieden.


Anmelden zum Antworten