Wo sollte man assert benutzen?



  • @Mastah: Klar, ich hab auch immer unreferenzierte Variablen in meinem Code.

    davie schrieb:

    warum sagst du dann nicht selbst einfach:
    das verhalten der funktion ist undefiniert, falls argument1 == 0.

    Gegenfrage: Und warum nicht "wirft eine Exception, falls ... " ?!
    Schau mal diese Methode hier an.

    If this parameter is NULL ...
    If this argument is NULL ...
    If this argument is NULL ...

    Das ist übrigens eine Methode, die man _sehr_ häufig aufruft, wenn man diese Klasse nutzt. Diese Methode erstellt Polygone, legt Texturen darüber, verrechnet ein paar Sachen mit der Transformationsmatrix, rechnet Bildschirmkoordinaten in Weltkoordinaten um - und macht ein paar if-Abfragen. Das wird bestimmt die ganze Performance killen. 🙄

    Es gibt einfach keinen Grund, da rum zu geizen, wenn es nicht grad was simples wie sqrt ist.

    EDIT: Link war falsch.



  • da ist es etwas anderes, da hier NULL als Option benutzt wird und nicht als Fehler.



  • Komm mal weg von Deinem DX-Beispiel, das ist aus zwei Gründen nämlich nicht repräsentativ:

    1. Man mag von MS halten was man will, aber im gute Schnittstellen definieren sind sie wahrlich keine Meister. Wenn ich sehen will, wie man ne gute Lib schreibt, dann werf ich nen Blick auf die STL.
      Nur weil die MFC von CObject erbt ist das nicht gleich gutes Design.

    2. DX ist eine Bibliothek, die direkt auf die Hardware zugreift. Sozusagen am OS vorbei. Daher ist es wichtig, daß sie falsche Aufrufe erkennt, denn damit kann man nicht nur die eigene Applikation zum Absturz bringen, sondern die Integrität des gesamten Systems beeinflussen. Und das darf ein Betriebssystem niemals zulassen.

    Wobei ich es dennoch mal auf einen Versuch ankommen lassen würde, die von Dir genannte Methode mit 0 als erstem Parameter aufzurufen... und bitte mal im Release, bin gespannt, was da passiert.

    MfG Jester



  • Sie liefert einen FAILED-Wert zurück. Ich hab auch die Release Version vom SDK installiert.

    @kingruedi: Nein, das ist nichts anderes. Wenn NULL keinen Sinn hier machen würde, würde die Methode fehlschlagen, aber sie würde keinen Mist machen.



  • Optimizer schrieb:

    @Mastah: Klar, ich hab auch immer unreferenzierte Variablen in meinem Code.

    Aus deiner Ironie schließe ich, dass du gemerkt hast wo dein Fehler lag?



  • Optimizer schrieb:

    @kingruedi: Nein, das ist nichts anderes. Wenn NULL keinen Sinn hier machen würde, würde die Methode fehlschlagen, aber sie würde keinen Mist machen.

    Interessant, du schließt also aus der Tatsache, dass es Funktionen gibt bei denen man NULL als Parameter übergibt, wenn man etwas nicht genauer eingrenzen möchte (ähnlich wie default-Parameter), dass man immer die Parameter überprüfen sollte? Irgendwie vergleichst du gerade Äpfel mit Birnen.



  • MaSTaH schrieb:

    Optimizer schrieb:

    @Mastah: Klar, ich hab auch immer unreferenzierte Variablen in meinem Code.

    Aus deiner Ironie schließe ich, dass du gemerkt hast wo dein Fehler lag?

    Mein Fehler?? Wenn ich sage, es führt zu ner Acces Violation, dann kannst du davon ausgehen, dass ich die Variable benutzt habe. Oder glaubst du, dass ich dich anlüge? Ich weiss doch selber, dass ein NULL-Pointer an sich noch nichts böses ist.



  • Optimizer schrieb:

    MaSTaH schrieb:

    Optimizer schrieb:

    @Mastah: Klar, ich hab auch immer unreferenzierte Variablen in meinem Code.

    Aus deiner Ironie schließe ich, dass du gemerkt hast wo dein Fehler lag?

    Mein Fehler?? Wenn ich sage, es führt zu ner Acces Violation, dann kannst du davon ausgehen, dass ich die Variable benutzt habe.

    Dass du die Variable benutzt hast deckt sich aber nicht mit der Aussage, dass die Nullreferenz alleine durch ihre Existenz eine Access-Violation ausgelöst haben soll. Ist ja auch egal.



  • es ist doch eigentlich so (etwas schwarz/weiss): assert ist zur fehler(bug)suche und ausnahmebehandlung zur laufzeit(benutzer)problembehandlung, und dies sind zwei ganz unterschiedliche sachen

    programmierte fehler können beim kompilieren und zur laufzeit mit assert erkannt werden, dies sind bugs, die eigentlich nie hätten auftreten dürfen und müssen behoben werden, dafür wird auch die debugversion des programms benutzt, in der releaseversion sind diese programmfehler nicht mehr enthalten, da sie vorher schon durch die debugversion und die asserts gefunden sind, wenn ein assert nicht anschlägt, dürfte ja auch ein anderer test, z.b. in der releaseversion, an gleicher stelle nicht anschlagen, höchstens die stelle wo das assert sich befindet wurde vorher nicht richtig mit der debugversion getestet, aber das sollte wohl erfolgt sein (oder?), der test in der releaseversion z.b. mit ausnahmebehandlung ist bei dieser art von fehler damit ja wohl überflüssig

    (wenn man diese tests doch in der releaseversion macht, gibt es aber bei der ausnahmebehandlung unschöne bespiele in einigen programmen, z.b. bei den unrealengine spielen finde ich es sehr sinnlos, wenn irgendein programmierfehler auftritt, welchen der benutzer garnicht beeinflussen kann, und sich dann das spiel mit einer nicht hilfreichen ausnahmemeldung beendet, besser wäre es, wenn sie den fehler vorher mit assert bei der entwicklung, statt beim benutzer mit einer ausnahme, gefunden hätten,
    da wäre wohl eine defensivere art der tests und behandlung sinnvoller gewesen, das spiel sollte trotzdem weiterlaufen und diesen fehler zwar loggen aber sonst stillscheigend behandelt/nicht beachtet/defensiv handhaben und nicht sich einfach sinnlos beenden,
    die quakeengine spiele sind in dieser beziehung stabiler)

    fehler die bei der benutzung des programms auftreten, z.b. fehlerhafte benutzereingaben, defekte dateien, ....., müssen immer in beiden versionen (debug und release) behandelt werden, dies sind keine programmierfehler, also nicht mit assert sondern durch "normale" fehlerbehandlung oder mittels durch ausnahmebehandlung impl. fehlerbehandlung,
    die behandlung sollte aber ein zuverlässiges verhalten des programms weiterermöglichen, und nicht mit einem absturz oder eine ausnahme beendet werden, so das der benutzer z.b. nicht seine daten verliert



  • MaSTaH schrieb:

    Dass du die Variable benutzt hast deckt sich aber nicht mit der Aussage, dass die Nullreferenz alleine durch ihre Existenz eine Access-Violation ausgelöst haben soll. Ist ja auch egal.

    Das habe ich auch nicht behauptet. Ich habe die Variable selbstverständlich benutzt, weil eine Referenz (zwar idR über Zeiger implementiert) nichts anderes ist, als ein anderer Name. Die Variable (in dem Fall der Pointer) und die Referenz darauf müssen jederzeit austauschbar sein.
    Das war doch von Anfang an klar, dass die bloße Existenz keinen Fehler auslöst, genauso wie der NULL-Zeiger keinen Fehler auslöst.



  • Optimizer schrieb:

    @kingruedi: Nein, das ist nichts anderes. Wenn NULL keinen Sinn hier machen würde, würde die Methode fehlschlagen, aber sie würde keinen Mist machen.

    Nein, sie schlägt nicht fehl. Wie bereits gesagt, ist das so etwas wie Default Parameter

    If this parameter is NULL, then the entire source image is used for the sprite.

    If this argument is NULL, the point (0,0,0) is used, which is the upper-left corner.

    If this argument is NULL, the point (0,0,0) is used, which is the upper-left corner.

    (Quelle: MSDN)

    niergend wo steht etwas von Access Violation.

    Das ist das gleiche wie zB. in C++

    void draw_point(const color &c=black);
    


  • Es gibt ja auch Parameter, die nicht NULL sein dürfen, das haben wir ja vorhin ausprobiert. Da schlägt die Funktion auch fehl, sie liefert einen Fehlerwert zurück.



  • @Optimizer: Wie schade, daß Du meinen Beitrag ignorierst. 😞



  • Ich habe doch den Test gemacht (gleich der nächste Post). 😕

    Die Methode liefert zurück, dass sie fehlgeschlagen ist.



  • Um es kurz zu machen zitiere ich mich mal eben selbst.

    Jester schrieb:

    Komm mal weg von Deinem DX-Beispiel, das ist aus zwei Gründen nämlich nicht repräsentativ:

    1. Man mag von MS halten was man will, aber im gute Schnittstellen definieren sind sie wahrlich keine Meister. Wenn ich sehen will, wie man ne gute Lib schreibt, dann werf ich nen Blick auf die STL.
      Nur weil die MFC von CObject erbt ist das nicht gleich gutes Design.

    2. DX ist eine Bibliothek, die direkt auf die Hardware zugreift. Sozusagen am OS vorbei. Daher ist es wichtig, daß sie falsche Aufrufe erkennt, denn damit kann man nicht nur die eigene Applikation zum Absturz bringen, sondern die Integrität des gesamten Systems beeinflussen. Und das darf ein Betriebssystem niemals zulassen.

    1. ist zwar etwas schwächer, aber 2) kannst Du nicht ernsthaft ignorieren, insofern verstehe ich nicht, warum Du bei dem Beispiel bleibst.


  • 2.) Stimmt so nicht. Auf die Hardware zugreifen tun nur Treiber, das sind die einzigen Programme, die wirklich ein System zum Absturz bringen können. Wenn eine DX-Funktion auf NULL zugreift, wird sie vermutlich genauso gekickt wie jedes andere Programm.
    Aber darum geht es nicht. Ich will, dass meine Libs, Klassen, whatever sicher sind, IMMER. Und ob ich jetzt dazu - wie vorgeschlagen - asserts auch im Release verwende oder eine if-Abfrage tut da nicht wirklich was zur Sache.

    ---------
    Wir drehen uns ständig im Kreis, ich habe doch bereits ausführlich dargelegt, für was ich asserts verwende. Für Situationen, die ich voll und ganz kontrollieren kann, wo meine Programmlogik sicherstellt, dass irgendetwas niemals passiert. -> asserts sind völlig "unnötig", sie erfüllen keine Funktion, sondern sind nur eine Bestätigung, dass meine Programmlogik korrekt ist.

    Du verwendest asserts auch, um Situationen zu kontrollieren, die du nicht vollständig unter Kontrolle hast und gehst davon aus, dass spätestens beim Release deine Lib richtig benutzt wird. Vermutlich (ein anderer Grund für diese Annahme fällt mir nicht ein) aus Performancegründen.
    ---------

    Aus Performancegründen würde ich eine Prüfung nur entfernen, wenn sie zweifelsfrei bei einer Methode der Flaschenhals ist. Ich möchte noch einmal klarstellen, dass ich die Prüfungen auch nur einmal mache. Wenn meine Methode danach noch andere, interne Methoden aufruft, gibt es keine Prüfungen mehr mit Exceptions.

    1.) Zu MS und DX: Ich finde die Vorgehensweise von MS gut, sie entspricht der meinen, außer dass die wahrscheinlich wegen C mit Rückgabewerten statt Exceptions arbeiten (In Managed DX wird mit Exceptions gearbeitet).

    Im Grunde sind es nur unterschiedliche Ansichten, ich will immer die Sicherheit, dass meine Lib keinen Murks baut, und verzichte nur im Zweifelsfall auf eine Prüfung. Es kommt ja gar nicht darauf an, ob ich das mit Exceptions oder sonstwie mache. Du sagst, es reicht, im Debug Build zu prüfen, dann bieten sich asserts wohl an.



  • Optimizer schrieb:

    Aber darum geht es nicht. Ich will, dass meine Libs, Klassen, whatever sicher sind, IMMER.

    Aus reinem Interesse, wie gehst du mit Thread-Sicherheit um?



  • Ich denke die Diskussion macht eh wenig Sinn. Wenn Optimizer es für nötig hält ständig alles überall zu prüfen, dann bringt es auch nichts jetzt auf ihn einzureden. Auch wenn es für den Rest von uns logisch scheint, dass man Eingaben lieber am Ort der Eingabe prüft und auf den Stupiden-Prüf-Overhead im Release verzichtet.



  • kingruedi schrieb:

    Ich denke die Diskussion macht eh wenig Sinn. Wenn Optimizer es für nötig hält ständig alles überall zu prüfen, dann bringt es auch nichts jetzt auf ihn einzureden. Auch wenn es für den Rest von uns logisch scheint, dass man Eingaben lieber am Ort der Eingabe prüft und auf den Stupiden-Prüf-Overhead im Release verzichtet.

    Ein wahres Wort. 😃
    Wie gesagt, wenn eine Prüfung mal wirklich der Flaschenhals sein sollte, dann entferne ich sie schon auch.

    @void: Ich hab mich mit Threads noch nicht auseinandergesetzt (hey ich lern grad 3 Sprachen gleichzeitig 😉 ).



  • Optimizer schrieb:

    wie gesagt, wenn eine Prüfung mal wirklich der Flaschenhals sein sollte, dann entferne ich sie schon auch.

    Und wie machst Du das, wenn zwei Projekt die Lib benutzen, die eine verläßt sich drauf, daß die Checks durchgeführt werden, für die andere ist es zu lahm... machst Du dann ne Kopie und modifizierst eine? Wie erklärst Du dann Deinem Chef, daß in Zukunft zwei Libs gewartet werden müssen? Aber auch das hatte ich oben schonmal geschrieben.

    Und jetzt geb ich es glaub ich auf.

    MfG Jester


Anmelden zum Antworten