assert oder exceptions



  • ..... 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.



  • ttestr schrieb:

    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?

    Die Frage ist, was diese Klasse macht. Öffnet sie eine Datei? Dann würde ich falls das Öffnen der Datei fehlschlägt eine Exception werfen. Ob das nun daran liegt, das der String leer ist oder die Datei einfach nicht existiert, spielt dabei keine Rolle, da es ja primär darum geht, die Datei zu öffnen.

    Übrigens solltest du nicht solche Mikrooptimierungen durchführen. Schließlich weißt du gar nicht, ob es tatsächlich einen so enormen Geschwindigkeitsverlust mit sich bringt...



  • ttestr schrieb:

    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?

    Für mich ganz klar: Exception.
    Sollen wir abstimmen? 😉

    Stefan.



  • DStefan schrieb:

    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.

    Dein Link bestätigt aber eher meine Aussage. Z.B. dieses Code Schnippsel:

    int strlenChecked(char* s) {
      assert(s != NULL);
      return strlen(s);
    }
    

    Das ist ja genau mein Fall. Der Parameter s hat einen falschen Wert => assert().
    Spricht eigentlich irgendwas dagegen, alle Parameterchecks mit assert() ab zu frühstücken?



  • ttestr schrieb:

    DStefan schrieb:

    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.

    Dein Link bestätigt aber eher meine Aussage. Z.B. dieses Code Schnippsel:

    int strlenChecked(char* s) {
      assert(s != NULL);
      return strlen(s);
    }
    

    Das ist ja genau mein Fall. Der Parameter s hat einen falschen Wert => assert().
    Spricht eigentlich irgendwas dagegen, alle Parameterchecks mit assert() ab zu frühstücken?

    Och neee... Jetzt aber! Zitat:

    Wikipedia schrieb:

    Durch die Formulierung einer Zusicherung bringt der Entwickler eines Programms seine Überzeugung über bestimmte Bedingungen während der Laufzeit eines Programms zum Ausdruck und lässt sie Teil des Programms werden. Er trennt diese Überzeugungen von den normalen Laufzeitumständen ab und nimmt diese Bedingungen als stets wahr an. Abweichungen hiervon werden nicht regulär behandelt, damit die Vielzahl möglicher Fälle nicht die Lösung des Problems vereitelt [...]

    Hervorhebung von mir.

    Stefan.



  • ttestr schrieb:

    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?

    Die Funktion wirft eh eine FileNotFoundException, wenn das Laden nicht klappte. Das assert(!filename.empty()) ist nur ein zusätzlicher Schutz, um einen typischen Programmierfehler besser jagen zu können, der das Programm in keiner weise sicherer oder unsicherer macht. Klares assert.



  • DStefan schrieb:

    Für mich ganz klar: Exception.
    Sollen wir abstimmen? 😉

    Aber nur, wenn fricky mitspielen darf.



  • ttestr schrieb:

    DStefan schrieb:

    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.

    Dein Link bestätigt aber eher meine Aussage. Z.B. dieses Code Schnippsel:

    int strlenChecked(char* s) {
      assert(s != NULL);
      return strlen(s);
    }
    

    Das ist ja genau mein Fall. Der Parameter s hat einen falschen Wert => assert().
    Spricht eigentlich irgendwas dagegen, alle Parameterchecks mit assert() ab zu frühstücken?

    Das der Parameter NULL ist, ist aber kein "echter" Fehler, sondern einfach Dummheit oder es war schon spät... Damit man sowas schneller findet nutzt man eben assert()... Wenn du hingegen eine Datei nicht öffnen kannst, weil sie schreibgeschützt ist oder nicht existiert dann ist das ein "richtiger" Fehler, den man zumindest im Konstruktor nur mit einer Exception vernünftig behandeln kann...



  • DStefan schrieb:

    Wikipedia schrieb:

    Durch die Formulierung einer Zusicherung bringt der Entwickler eines Programms seine Überzeugung über bestimmte Bedingungen während der Laufzeit eines Programms zum Ausdruck und lässt sie Teil des Programms werden. Er trennt diese Überzeugungen von den normalen Laufzeitumständen ab und nimmt diese Bedingungen als stets wahr an. Abweichungen hiervon werden nicht regulär behandelt, damit die Vielzahl möglicher Fälle nicht die Lösung des Problems vereitelt [...]

    Hervorhebung von mir.
    Stefan.

    Ahm. Ja. Ich gehe stets davon aus, daß der string nicht leer ist. Ich mache keine Anstalten, Abweichungen davon regulär zu behandeln.



  • @DStefan: Und was soll die Markierung jetzt groß zeigen? Der Code benutzt ein assert() um sicherzustellen, dass die Parameter valide sind. Genau wie in meinem Beispiel.

    Es gibt tausende Beispiel.
    Z.B. folgende Funktion:
    void foo(const vector3f& v) { }
    Der übergebene Vektor v MUSS normalisiert sein.

    Ich habe 2 Möglichkeiten:
    assert( v.getLength() == 1);

    Vorteil: getLength() ist richtig teuer (Wurzel)
    oder:
    if(v.GetLength() == 1)
    throw IllegalParameterException();

    Auch hier tendiere ich wieder stark zu assert().



  • Der Vorteil is natürlich ein Nachteil 😉


Anmelden zum Antworten