assert oder exceptions
-
Hallo,
ich bin mir oft nicht ganz sicher, ob ich besser ein assert() benutze oder eine exception werfe.
Was zb wenn man einer Methode NUR die Zahlen 0-100 übergeben darf:
float method(int p) { }
mach ich da jetzt ein assert() am Anfang von method() oder werfe ich eine IllegalParameterException?
-
eher assert. kommt ein bißchen drauf an. eher assert.
-
Was ich nicht raffe: Wieso gibt es überhaupt eine exception wie IllegalParameterException? Im fertigen release build Programm sollten doch IllegalParameterExceptions garnicht mehr vorkommen können?
-
ttestr schrieb:
Hallo,
ich bin mir oft nicht ganz sicher, ob ich besser ein assert() benutze oder eine exception werfe.
Was zb wenn man einer Methode NUR die Zahlen 0-100 übergeben darf:
float method(int p) { }
mach ich da jetzt ein assert() am Anfang von method() oder werfe ich eine IllegalParameterException?
Kommt drauf an:
Eine Assertion ist eine Zusicherung: Man weiß, dass etwas so oder so ist. Sollte die Assertion fehlschlagen, ist dies ein Hinweis auf einen internen Fehler, etwa darauf, dass eine Klasseninvariante nicht einghalten wurde. Konsequenterweise wird assert() in der Release-Version deines Programms (wenn also NDEBUG definiert ist) ausgeschaltet.
Falls method() in der öffentlichen Schnittstelle deiner Klasse verfügbar ist, weißt du nicht, dass p im Wertebereich liegt. Deshalb würde ich in diesem Fall nicht assert() verwenden, sondern tatsächlich eine passende Exception werfen.
Stefan.
-
Das ist wohl Geschmackssache, ich nehme
assert()
sehr gerne für Checks, die ich nur im Debugmodus haben will und dann im Release wegen Performancegründen nicht mehr (assert()
tut ja nur was, solange nichtNDEBUG
definiert wurde). Finde ich recht komfortabel.Es kommt auch auf deine Funktion an. Macht es Sinn, eine entsprechende Exception zu fangen und dann entsprechend zu reagieren und das Programm weiterlaufen zu lassen, oder ist nach einem falschen Funktionsaufruf eh alles Schrott, so dass du das Programm gleich beenden musst?
mfg
-
Naja, method() ist schon in der öffentlichen Schnittstelle. Aber ich würde doch klipp und klar in die Doku von method() schreiben, dass der Parameter NUR in [0,4] liegen darf. Wenn der Programmierer jetzt method(5) aufruft, dann ist das doch ein Programmierfehler, der im Release Modus nicht mehr auftreten darf, oder?
-
ttestr schrieb:
Was ich nicht raffe: Wieso gibt es überhaupt eine exception wie IllegalParameterException? Im fertigen release build Programm sollten doch IllegalParameterExceptions garnicht mehr vorkommen können?
Naja, man wollte wohl zulassen, daß die C++-Programmiererschaft feststellt, daß Java doch besser ist und wie in Java programmiert.
-
ttestr schrieb:
Naja, method() ist schon in der öffentlichen Schnittstelle. Aber ich würde doch klipp und klar in die Doku von method() schreiben, dass der Parameter NUR in [0,4] liegen darf. Wenn der Programmierer jetzt method(5) aufruft, dann ist das doch ein Programmierfehler, der im Release Modus nicht mehr auftreten darf, oder?
Erfahrungsgemäß nicht. Oder kannst du dir wirklich sicher sein, dass wirklich jede Verwendung der Methode während der Debug-Phase getestet wurde? Ich glaube an sowas nicht - es sei denn in eher trivialen Fällen.
Ich bin in dieser Hinsicht ein Sicherheits-Fanatiker, prüfe also in der öffentlichen Schnittstelle immer auf Einhaltung der Preconditions und werfe eine passende Exception, sollten sie nicht eingehalten worden sein. Die Kosten sind in der Regel kaum der Rede wert. Dem gegenüber steht der Nutzen, dass es an der richtigen Stelle knallt.
Stefan.
-
volkard schrieb:
ttestr schrieb:
Was ich nicht raffe: Wieso gibt es überhaupt eine exception wie IllegalParameterException? Im fertigen release build Programm sollten doch IllegalParameterExceptions garnicht mehr vorkommen können?
Naja, man wollte wohl zulassen, daß die C++-Programmiererschaft feststellt, daß Java doch besser ist und wie in Java programmiert.
So ein schwchsinn...
Gerade du solltest doch wissen, dass man Funktionen mit variablen Parametern programmieren kann. Diese Exception hat definitiv einen Sinn.
-
DStefan schrieb:
ttestr schrieb:
Naja, method() ist schon in der öffentlichen Schnittstelle. Aber ich würde doch klipp und klar in die Doku von method() schreiben, dass der Parameter NUR in [0,4] liegen darf. Wenn der Programmierer jetzt method(5) aufruft, dann ist das doch ein Programmierfehler, der im Release Modus nicht mehr auftreten darf, oder?
Erfahrungsgemäß nicht. Oder kannst du dir wirklich sicher sein, dass wirklich jede Verwendung der Methode während der Debug-Phase getestet wurde? Ich glaube an sowas nicht - es sei denn in eher trivialen Fällen.
Ich bin in dieser Hinsicht ein Sicherheits-Fanatiker, prüfe also in der öffentlichen Schnittstelle immer auf Einhaltung der Preconditions und werfe eine passende Exception, sollten sie nicht eingehalten worden sein. Die Kosten sind in der Regel kaum der Rede wert. Dem gegenüber steht der Nutzen, dass es an der richtigen Stelle knallt.
Ich kann dich schon nachvollziehen, aber ich sehe da 2 Probleme: Erstens kann es sich tatsächlich auf die Performance auswirken, wenn du oft Dinge prüfst (bei meiner Anwendung ist die Performanz SEHR wichtig). 2. brauchst du bei deiner Logik nazue NIE ein assert()Ich bin verwirrt
Stefan.
-
DStefan schrieb:
Ich bin in dieser Hinsicht ein Sicherheits-Fanatiker, prüfe also in der öffentlichen Schnittstelle immer auf Einhaltung der Preconditions und werfe eine passende Exception, sollten sie nicht eingehalten worden sein. Die Kosten sind in der Regel kaum der Rede wert. Dem gegenüber steht der Nutzen, dass es an der richtigen Stelle knallt.
Stefan.
Sry, hab falsch zitiert.
Ich kann dich schon nachvollziehen, aber ich sehe da 2 Probleme: Erstens kann es sich tatsächlich auf die Performance auswirken, wenn du oft Dinge prüfst (bei meiner Anwendung ist die Performanz SEHR wichtig). 2. brauchst du bei deiner Logik nazue NIE ein assert().
Ich tendiere im Moment dazu, ALLE Parameterchecks mit assert() durchzuführen und NIE eine IllegalParameterException zu werfen. Meine Logik ist: Kann ein Fehler auch im Release Build auftreten => Exception. Nur im Debug Build, weil der Programmierer was versaut hat: assert(). Ist das so falsch?
Ich bin verwirrt
-
..... schrieb:
Gerade du solltest doch wissen, dass man Funktionen mit variablen Parametern programmieren kann. Diese Exception hat definitiv einen Sinn.
Aber die Funktionen mit so variabler Bedeutung, daß man nicht dokumentieren kann, was erlaubt ist, und was nicht, sind schon recht selten.
-
ttestr schrieb:
DStefan schrieb:
ttestr schrieb:
Naja, method() ist schon in der öffentlichen Schnittstelle. Aber ich würde doch klipp und klar in die Doku von method() schreiben, dass der Parameter NUR in [0,4] liegen darf. Wenn der Programmierer jetzt method(5) aufruft, dann ist das doch ein Programmierfehler, der im Release Modus nicht mehr auftreten darf, oder?
Erfahrungsgemäß nicht. Oder kannst du dir wirklich sicher sein, dass wirklich jede Verwendung der Methode während der Debug-Phase getestet wurde? Ich glaube an sowas nicht - es sei denn in eher trivialen Fällen.
Ich bin in dieser Hinsicht ein Sicherheits-Fanatiker, prüfe also in der öffentlichen Schnittstelle immer auf Einhaltung der Preconditions und werfe eine passende Exception, sollten sie nicht eingehalten worden sein. Die Kosten sind in der Regel kaum der Rede wert. Dem gegenüber steht der Nutzen, dass es an der richtigen Stelle knallt.
Ich kann dich schon nachvollziehen, aber ich sehe da 2 Probleme: Erstens kann es sich tatsächlich auf die Performance auswirken, wenn du oft Dinge prüfst (bei meiner Anwendung ist die Performanz SEHR wichtig). 2. brauchst du bei deiner Logik nazue NIE ein assert()Ich bin verwirrt
Stefan.
1. Bennen deine Funktion angemessen, um Missverständnisse zu vermeiden.
2. Bennen die Parameter angemessen, um Missverständnisse zu vermeiden.
3. Beschreibe die Einschränkungen deiner Funktion korrekt.
4. Nutze assert(), um Fehler auzuschließen. Jemand der den Debug-Modus nicht nutzt hat imho selber Schuld!
Alternativ zu Punkt 4:
Überprüfe, ob der von dir gewählte Typ
int
überhaupt eine gute Wahl ist.Wenn es nur 5 Möglichkeiten gibt, so reicht eventuell ein
enum
? Wenn dem so ist: Benutze es und alles sollte in Ordnung sein.Ansonsten musst du evtl. mit mehr Details rausrücken, was deine Funktion macht, etc. Vielleicht läßt sich da einiges verbessern.
-
..... schrieb:
volkard schrieb:
ttestr schrieb:
Was ich nicht raffe: Wieso gibt es überhaupt eine exception wie IllegalParameterException? Im fertigen release build Programm sollten doch IllegalParameterExceptions garnicht mehr vorkommen können?
Naja, man wollte wohl zulassen, daß die C++-Programmiererschaft feststellt, daß Java doch besser ist und wie in Java programmiert.
So ein schwchsinn...
Gerade du solltest doch wissen, dass man Funktionen mit variablen Parametern programmieren kann. Diese Exception hat definitiv einen Sinn.
Funktionen mit variablen Parametern haben in C++ keinen großen Platz, weil sie nur mit PODs funktionieren. Das wäre also kein Argument für die Exceptions.
-
ttestr schrieb:
DStefan schrieb:
Ich bin in dieser Hinsicht ein Sicherheits-Fanatiker, prüfe also in der öffentlichen Schnittstelle immer auf Einhaltung der Preconditions und werfe eine passende Exception, sollten sie nicht eingehalten worden sein. Die Kosten sind in der Regel kaum der Rede wert. Dem gegenüber steht der Nutzen, dass es an der richtigen Stelle knallt.
Stefan.
Sry, hab falsch zitiert.
Ich kann dich schon nachvollziehen, aber ich sehe da 2 Probleme: Erstens kann es sich tatsächlich auf die Performance auswirken, wenn du oft Dinge prüfst (bei meiner Anwendung ist die Performanz SEHR wichtig). 2. brauchst du bei deiner Logik nazue NIE ein assert().
Ich tendiere im Moment dazu, ALLE Parameterchecks mit assert() durchzuführen und NIE eine IllegalParameterException zu werfen. Meine Logik ist: Kann ein Fehler auch im Release Build auftreten => Exception. Nur im Debug Build, weil der Programmierer was versaut hat: assert(). Ist das so falsch?
Ich bin verwirrt
Nun, falls Performance tatsächlich ein Problem ist, musst du wohl die Prüfung fallen lassen. Aber bist du dir sicher, dass dies wirklich so ist?
Der zweite Punkt stimmt nicht. Ich brauche assert(), um Fakten zuzusichern und darauf aufmerksam zu werden, wenn beispielsweise innerhalb der Klasse etwas falsch gemacht wurde, also bei Verletzung der Klassen-Invariante. Außerdem zeigen Assertions einem Leser des Codes die Voraussetzungen/Invarianten deutlich an. Das entlastet beispielsweise beim Debuggen.
Exceptions brauche ich, wenn Dinge von außen an die Klasse herangetragen werden. Diese unterliegen ja nicht der Kontrolle der Klasse. Selbst wenn ich also meine Klasse korrekt programmiert habe, kann es immer noch sein, dass sie falsch verwendet wird. Dann kriegt der Aufrufer von mir eine Exception.
Stefan.
-
DStefan schrieb:
Der zweite Punkt stimmt nicht. Ich brauche assert(), um Fakten zuzusichern und darauf aufmerksam zu werden, wenn beispielsweise innerhalb der Klasse etwas falsch gemacht wurde, also bei Verletzung der Klassen-Invariante. Außerdem zeigen Assertions einem Leser des Codes die Voraussetzungen/Invarianten deutlich an. Das entlastet beispielsweise beim Debuggen.
Exceptions brauche ich, wenn Dinge von außen an die Klasse herangetragen werden. Diese unterliegen ja nicht der Kontrolle der Klasse. Selbst wenn ich also meine Klasse korrekt programmiert habe, kann es immer noch sein, dass sie falsch verwendet wird. Dann kriegt der Aufrufer von mir eine Exception.
Das kann man so machen, aber muß man nicht. Ich mach's nicht so.
-
volkard schrieb:
DStefan schrieb:
Der zweite Punkt stimmt nicht. Ich brauche assert(), um Fakten zuzusichern und darauf aufmerksam zu werden, wenn beispielsweise innerhalb der Klasse etwas falsch gemacht wurde, also bei Verletzung der Klassen-Invariante. Außerdem zeigen Assertions einem Leser des Codes die Voraussetzungen/Invarianten deutlich an. Das entlastet beispielsweise beim Debuggen.
Exceptions brauche ich, wenn Dinge von außen an die Klasse herangetragen werden. Diese unterliegen ja nicht der Kontrolle der Klasse. Selbst wenn ich also meine Klasse korrekt programmiert habe, kann es immer noch sein, dass sie falsch verwendet wird. Dann kriegt der Aufrufer von mir eine Exception.
Das kann man so machen, aber muß man nicht. Ich mach's nicht so.
Ich weiß. Die Diskussion hatten wir schonmal (vor drei Jahren oder so?) Ich habe mich seitdem nicht gebessert
Der Vollständigkeit halber sollte man wohl anmerken, dass es auch in den Standard-Bibliotheken selten so gehandhabt wird. Da hat man dann einfach undefined behavior, wenn man nicht brav ist.
Stefan.
-
@DStefan: Ich finde du siehst assert() bissi zu sehr als reine "interne" Absicherungsmaßnahme. Wenn du eine öffentliche Schnittstelle hast, dann haben viele Methoden klare Richtlinien. Wenn der Anwender die nicht erfüllt, dann ist das ein Programmierfehler, der IMO auch mit assert() behandelt werden kann.
Hm, aber ich seh schon, dass es eine klare Antwort nicht gibt. Für jemanden wie mir mit sehr, sehr wenig Erfahrung ist es halt oft schwer abzuwägen was das richtige ist:/
-
ttestr schrieb:
@DStefan: Ich finde du siehst assert() bissi zu sehr als reine "interne" Absicherungsmaßnahme. Wenn du eine öffentliche Schnittstelle hast, dann haben viele Methoden klare Richtlinien. Wenn der Anwender die nicht erfüllt, dann ist das ein Programmierfehler, der IMO auch mit assert() behandelt werden kann.
Hm, aber ich seh schon, dass es eine klare Antwort nicht gibt. Für jemanden wie mir mit sehr, sehr wenig Erfahrung ist es halt oft schwer abzuwägen was das richtige ist:/
Dann zeig doch einfach deine konkrete Funktion? Wenn du eine Funktion hast, die tatsächlich nur 5 Werte zuläßt, dann löse das doch mit enum...
-
BBBB schrieb:
Dann zeig doch einfach deine konkrete Funktion? Wenn du eine Funktion hast, die tatsächlich nur 5 Werte zuläßt, dann löse das doch mit enum...
Mir ging es mehr um den generellen Ansatz. Mein Beispiel hab ich frei erfunden.
Ein konkreter Fall bei mir:
Foo::Foo(const std::string filename) { ... }
Der Ctor wird die Datei laden. Was mache ich, wenn der Benutzer einen Leerstring "" übergibt? assert() oder exception?
-
ttestr schrieb:
@DStefan: Ich finde du siehst assert() bissi zu sehr als reine "interne" Absicherungsmaßnahme. Wenn du eine öffentliche Schnittstelle hast, dann haben viele Methoden klare Richtlinien. Wenn der Anwender die nicht erfüllt, dann ist das ein Programmierfehler, der IMO auch mit assert() behandelt werden kann.
Hm, aber ich seh schon, dass es eine klare Antwort nicht gibt. Für jemanden wie mir mit sehr, sehr wenig Erfahrung ist es halt oft schwer abzuwägen was das richtige ist:/
Nö, das seh nicht nur ich so, das ist common sense.
Kuckstu hier: de.wikipedia.org/wiki/Assertion_(Informatik)Stefan.