Findet ihr es gut das delete bei Null-Pointern definiertes Verhalten hat?
-
Ponto: Und wieso wäre dir das lieber? Das delete hat keine Funktion, na und? Ich seh da kein Problem drin. Abstürze sind sowieso schlecht. Eine Exception find ich in dem Fall auch nicht gut, da ja kein unerwartetes Verhalten auftritt (weil gar kein Verhalten auftritt). Bei std::terminate (war doch fürs Programm zu beenden oder?) weiß man auch nicht, was passiert ist. Ich kann mir schöneres vorstellen, als einen Bug zu suchen, der keiner ist.
-
Michael E. schrieb:
Ponto: Und wieso wäre dir das lieber? Das delete hat keine Funktion, na und? Ich seh da kein Problem drin. Abstürze sind sowieso schlecht. Eine Exception find ich in dem Fall auch nicht gut, da ja kein unerwartetes Verhalten auftritt (weil gar kein Verhalten auftritt). Bei std::terminate (war doch fürs Programm zu beenden oder?) weiß man auch nicht, was passiert ist. Ich kann mir schöneres vorstellen, als einen Bug zu suchen, der keiner ist.
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. Dann ist es gut, wenn der Compiler Code erzeugt, der sofort abschmiert.
Im Grunde erreiche ich sowas Ähnliches, indem ich Pointer nie auf Null setze, es sei denn es gehört zur Funktion der Klasse. Dann können Tools wie valgrind eher den Fehler in meiner Logik finden.
-
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.