Nullen setzten



  • PAD schrieb:

    Wie kann ich erreichen das ein Teil der asserts in der Release Version aktiv bleiben.

    das würde dann doch etwas peinlich sein, wenn der endbenutzer nach stundenlanger tipparbeit mit einer assertion und einem programmabruch abgefertigt werden würde 😉



  • Ich wuerde sowieso Vorschlagen, dass sich jeder sein eigenes assert() schreibt.

    Echt? Hast du dafür auch eine Begründung?



  • PAD logged out schrieb:

    Ich wuerde sowieso Vorschlagen, dass sich jeder sein eigenes assert() schreibt.

    Echt? Hast du dafür auch eine Begründung?

    Ja, assert ist böse



  • Vielleicht sollte da noch der Hinweis rein, dass man _dieses_ Assert dann besser nicht in Destruktoren verwenden sollte. Hab ich zumindest beim flüchtigen Überfliegen nicht sehen können.

    Zu dem Thema habe ich mir auch noch http://www.cuj.com/documents/s=8464/cujcexp0308alexandr/ gebookmarkt, aber bisher nicht gelesen 😉



  • mist, wollte gerade so eine klasse für mich schreiben wie es Shade beschrieben hat und dann die schlechte Nachricht von operator void. 🤡



  • Nur zur Klarstellung

    PAD logged out

    Das bin ich nicht



  • [quote=SHADE]Ich teste halt nur in der Debug Version - danach bin ich mir sicher, dass ich keine falschen Daten mehr habe. [/quote]

    Du Glücklicher, ich habs mit Geräten zu tun für die ich/wir auf ihre QualitätsPrüfProgramme schreiben. Diese haben auch digitale Kommunicationsschnittstellen und selbst DAU´s sind dagegen manchmal angenehme Zeitgenossen. Wenn einer der Prüflinge spinnt sind falsche Daten in Inhalt und Form eher die Regel als die Ausnahme.



  • operator void schrieb:

    Vielleicht sollte da noch der Hinweis rein, dass man _dieses_ Assert dann besser nicht in Destruktoren verwenden sollte.

    ein assert() in einem Destruktor?
    Wieso sollte so etwas vorkommen, bzw. inwiefern sollte dies schlechter sein als ein normales assert()?

    Ich hatte noch nie ein assert() in einem Dtor, aber selbst wenn es auftreten sollte wäre es immer noch besser als ein assert() - denn bei meinem Assert() kann es zu Resourcenlöchern kommen, beim echten ássert() kommt es dazu.

    Welche Lösung würdest du vorschlagen?

    Im Prinzip bleibt einem nichts anderes übrig als eine Exception zu werfen.



  • imho ist das im prinzip dann sowieso schon egal. 2 ausnahmen.. da stinkt was
    aber eventuell könnte man ein assert machen, das das programm nur abbricht, wenn uncaught_exception() false liefert



  • Was passiert denn, wenn eine Exception im Destruktor ausgelöst wird? Ist das dann undefiniertes Verhalten?



  • Noch eine Frage, Shade:

    Warum hast du hier exp nochmal geklammert?

    if(!(exp))
    


  • Shade Of Mine schrieb:

    ein assert() in einem Destruktor?
    Wieso sollte so etwas vorkommen, bzw. inwiefern sollte dies schlechter sein als ein normales assert()?

    Zum Beispiel habe ich eine Grafikengine und viele Texturen. Die Texturen müssen auf derselben Grafikengine erstellt und dann auch gelöscht werden. Eine Textur länger zu verwenden, als die Grafikengine existiert, ist illegal. Also überprüft der Dtor der Grafikengine, ob alle Texturen freigegeben sind - sind sie es nicht, hat entweder der Benutzer der Klassen (=ich) Mist bei der Resourcenfreigabe gemacht oder im Grafiksystem selbst ist ein Fehler. (Das ganze Texturmanagement ist intern auch nicht gerade einfach.) Viel mehr als terminate() bleibt einem da nicht mehr übrig: Wenn die Invarianten meiner Klassen nicht eingehalten sind, können sie eventuell nicht einmal freigegeben werden.
    Das Problem mit Dtoren ist dann noch, dass werfende Dtoren allgemein für schlechten Stil gehalten und deshalb in den meisten Überlegungen ignoriert werden. Viel Code (auch der von wiederum anderen Dtoren) verlässt sich einfach darauf, dass Dtoren nie werfen. Die Möglichkeiten für Undefined Behaviour breiten sich damit immer weiter aus.
    Da ist mir der der Standard-assert-Dialog lieber, der gleich Debugging anbietet, auch wenn man es ohne Debugger gestartet hat. Im schlimmsten Fall kosten mich die Leaks einen Reboot pro entdecktem Logikfehler, und die meisten Resourcen, die ich verwalte, sind nicht einmal so kritisch. Der Aspekt sieht aber natürlich bei jedem anders aus.



  • marco9 schrieb:

    Was passiert denn, wenn eine Exception im Destruktor ausgelöst wird? Ist das dann undefiniertes Verhalten?

    nein, aber wenn bereits eine exception im werfen ist, kann es probleme geben:

    class Gefaehrlich {
    public:
       ~Gefaehrlich () {
           throw "blub";
       }
    };
    
    int main () {
       try {
         Gefaehrlich g;
         throw "Hello World!";
       } catch (const char *c) {
         cout << c << '\n';
       }
    }
    

    kannst du mal ausprobieren. 2 exceptions gleichzeitig lassen std::terminate seine grausamen terminierungsanweisungen ausführen 😉
    absichern dagegen geht zb mit

    class GefahrGebannt {
    public:
       ~GefahrGebannt () {
         if (!uncaught_exception()) throw "Neue Exception!";
       }
    };
    

    aber das ist ebenso für manche programmierer, die davon ausgehen, das destruktoren niemals ausnahmen werfen, gefährlich.
    also lieber dtors nicht ausnahmen werfen lassen.

    zum thema resourcenfreigeben: man kann doch nicht im terminate_handler absicherungen unterbringen, oder? sinnvoll? lieber keine ausnahmen in dtoren?



  • @operator void:
    Und inwiefern ist da das terminate() besser als mein Assert() ?

    Bitte vergiss nicht, dass man bei meinem Assert() dann den Fehler abfangen kann und eine schöne Fehlermeldung ausgeben (und danach erst beenden).

    Wie davie ja schon erklärt hat kann es zu Problemen kommen wenn eine Exception einen Dtor verlässt. Aber bei einem terminate() wird garnichts zerstört.

    Ich bevorzuge da lieber die Variante mit den wenigeren Ressourcenlöchern. Wenn jemand eine bessere Variante kennt -> nur her damit.

    @marco9:
    Der Operator ! hat eine sehr starke Bindung
    Damit es da nicht zu Problemen kommt habe ich sicherheitshalber geklammert.

    @davie:
    uncaught_exception() ist in der Theorie natürlich recht praktisch, aber in der Praktit liefert es bei fast allen Compilern immer false 😞



  • hmm ich hab davon gehört und es mit dem gcc ausprobiert. da funktioniert es 🙂
    aber ob es das wirklich wert ist?



  • Shade Of Mine schrieb:

    @operator void:
    Und inwiefern ist da das terminate() besser als mein Assert() ?

    Mir sind potenzielle Resourcenleaks lieber als ein Haufen undefiniertes (und dabei auch unüberschaubares) Verhalten. Und wie gesagt, assert() verwende ich, um grundlegende Invarianten sicherzustellen und dafür ist es imho auch sehr brauchbar. Wenn ein assert fehlschlägt, ist die Möglichkeit des sauberen Aufräumens nicht gegeben. An der Stelle, wo in meinem Beispiel die Grafikengine merkt, dass die Texturen nicht ordnungsgemäß freigegeben wurden, kann sie einfach nicht viel Sinnvolleres mehr tun als den Fehler so klar wie möglich auszugeben und auf die Behebung des Fehlers durch mich zu warten. (Natürlich könnte man da noch einen komplizierten Mechanismus drumrum bauen, aber man kann die Texturen auch einfach richtig freigeben 😉 )



  • operator void schrieb:

    ein Haufen undefiniertes (und dabei auch unüberschaubares) Verhalten.

    wenn 2 exceptions geworfen werden, ist das aber nicht undefiniert. was meinst du?



  • Hallo,
    nur noch mal zur Erinnerung: uncaught_exception sagt nur, ob eine Exception gerade *aktiv* ist. Es sagt nicht, ob es sicher ist, eine Exception zu werfen.

    Ich halte es bei diesem Thema mit Herb Sutter: http://www.gotw.ca/gotw/047.htm

    Die Aufregung um die Resourcen-Löcher kann ich nicht teilen. Wenn in meinem Programm eine Assertion verletzt wird, dann sind Resourcenlöcher ein kleineres Problem. Eine Assertion ist ja eben *keine* Ausnahme (auch wenn man sie gut über den Ausnahmemechanismus implementieren kann).
    Es ist nichts auf das ich vorbereitet bin und auf das ich geregelt reagieren kann/will.
    Eine fehlgeschlagene Assertion ist ein Bug. Meldung/Aus/Zurück an den Schreibtisch. Häufig habe ich in diesem Moment einen Programmzustand der nicht definiert ist. D.h. aber auch, dass ich nicht alles ordentlich abbauen kann.
    Natürlich sollte man meiner Meinung nach versuchen, soviel wie möglich so sauber wie möglich zu beenden. Aber das wichtigste ist die fehlgeschlagene Assertion, nicht deren Behandlung.

    Ich lasse meine Assertions standardmäßig natürlich auch in der Release-Version an. Schließlich verschwinden Bugs nicht durch das Ausschalten des Debug-Flags 🙂



  • davie schrieb:

    wenn 2 exceptions geworfen werden, ist das aber nicht undefiniert. was meinst du?

    Nicht automatisch, aber viel Code verlässt sich einfach darauf, dass ein Destruktor keine Exception wirft - ich glaube, das fängt bei den STL-Containern an (finde die entsprechende Liste aber gerade nicht in der MSDN). Wenn man sich daran nicht hält, betritt man offiziell schon das Land des undefinierten Verhaltens.



  • Wenn man sich daran nicht hält, betritt man offiziell schon das Land des undefinierten Verhaltens.

    Nicht wirklich. Man betritt dann ein Land in dem alle Exception-Garantien *nicht* mehr gelten. Die STL-Container z.B. geben ihre Garantien nur unter bestimmten Voraussetzungen. Und eine davon ist, dass der Dtor der User-Klassen keine Exceptions schmeißt.

    Oder kurz: Dtoren die schmeißen sind böse.


Anmelden zum Antworten