Warnungen mit Exceptions?



  • Die du aber weder mit try&catch noch mit MessageBox() irgendwie posten kannst da dein ganzes Programm hängt 😉

    Egal, für Edit-Boxen gibts ja nun bereits schlauerweise eine maximale Zeichenanzahl.

    MfG SideWinder



  • otze schrieb:

    exceptions dürfen natürlich noch geworfen werden, aber soeine exception noch im releasecode rumzuschleppen ist wirklich unnötig 😉

    Nö.

    Exceptions sind Fehler, die man behandelt - folglich sind sie im Release Code auch noch enthalten.

    asserts sind Fehler, die nicht auftreten dürfen - folglich sind sie im Release Code nicht enthalten, da wir solche Fehler bereits beim Testen entfernt haben.

    Wenn ich eine Exception in der Release Version nicht mehr habe - wozu dann in der Testversion?? Dann tut es ein assert ja auch...



  • godlikebot schrieb:

    Normalerweise werden try/catch Blöcke doch nicht für einzelne Funktionen angelegt, sondern für einen ganzen Satz von Anweisungen. Um das so zu machen, müsste ich aber doch für jede Funktion einen try/catch Block schreiben.

    Eben nicht.
    Wieso sollte man soetwas schreiben?

    Mal abgesehen, dass man nicht by value fängt.

    Wäre in dieser Hinsicht C-Style Fehlerbehandlung nicht besser?

    Exakt. Wenn du überall ein try/catch hast, dann machen Exceptions keinen Sinn. Die Frage ist aber eher: macht dein Design Sinn?



  • Du solltest keine Klasse ScreenResInvalid haben sondern eine namens engine_exception (abgeleitet von std::exception). Das "Screen Resolution was invalid." steht dann besser in .what().

    Zu dem Übersichtsproblem meine ich nur: Möglichst keine Exceptions auftreten lassen. Unerwartete und tatsächlich unabfangbare Fehler (meine Engine ist zu dumm in den Fullscreen-Modus zu schalten, etc.) in einem großen try/catch-Block abfangen.

    MfG SideWinder



  • Shade of Mine schrieb:

    Eben nicht.
    Wieso sollte man soetwas schreiben?

    try
    {
        WasProbieren();
    }
    catch(...)
    {
        Reagieren();
    }
    
    try
    {
        WasAnderesProbieren();
    }
    catch(...)
    {
        AuchDaraufReagieren();
    }
    Und so weiter
    

    Kann man denn sagen, dass C-Style Fehlerbehandlung in C++ schlechterer Stil ist als Exceptions?



  • Shade Of Mine schrieb:

    otze schrieb:

    exceptions dürfen natürlich noch geworfen werden, aber soeine exception noch im releasecode rumzuschleppen ist wirklich unnötig 😉

    Nö.

    Exceptions sind Fehler, die man behandelt - folglich sind sie im Release Code auch noch enthalten.

    asserts sind Fehler, die nicht auftreten dürfen - folglich sind sie im Release Code nicht enthalten, da wir solche Fehler bereits beim Testen entfernt haben.

    Wenn ich eine Exception in der Release Version nicht mehr habe - wozu dann in der Testversion?? Dann tut es ein assert ja auch...

    assert ist für mich im code unfindbar, wenn ich auf fehlersuche bin, ein try/catch block fällt mir sofort ins auge.



  • SideWinder schrieb:

    Zu dem Übersichtsproblem meine ich nur: Möglichst keine Exceptions auftreten lassen. Unerwartete und tatsächlich unabfangbare Fehler (meine Engine ist zu dumm in den Fullscreen-Modus zu schalten, etc.) in einem großen try/catch-Block abfangen.

    Du meinst eine Mischung aus Exception für alle Funktionen, die "Lebenswichtig" für das Programm sind und C-Style für alles andere? Aber wäre es dann nicht ebenso gut, ganz auf Exceptions zu verzichten? Die paar kritischen Funktionen kann man ja auch auf ihren Rückgabewert überprüfen und daraufhin reagieren. Das würde auch der Einheitlichkeit der Engine dienen.



  • Nein, immer C++-Exception-Handling, aber SetResolution() wirft einfach keine Exception. Wenns nicht geht dann eben return + setzen eines Failbits, wie zB bei den C++-Streams.

    MfG SideWinder



  • @SideWinder:
    Was ist denn ein Failbit?



  • ios_base::iostate
    typedef T2 iostate;
    static const iostate badbit, eofbit, failbit, goodbit;
    The type is an enumerated type T2 that describes an object that can store stream state information. The distinct flag values are:

    badbit, to record a loss of integrity of the stream buffer
    eofbit, to record end-of-file while extracting from a stream
    failbit, to record a failure to extract a valid field from a stream
    In addition, a useful value is:

    goodbit, no bits set

    Also diese werden gesetzt und können dann mit zB cin.rdstate() gelesen werden.

    Die habens noch geschickter gemacht, die haben auch noch den op! überladen, der liefert rdstate()&failbit zurück:

    char a;
    while(!cin>>a) // wenn zB ein String eingegeben wurde wird failbit gesetzt
    {
        // Fehlermeldung ausgeben oder sonstwas tun
    }
    

    MfG SideWinder



  • Wieso alles Reparieren? Kannst du das etwa?

    btw: 800x700 gibts nicht also nehmen wir 800x600 ist natürlich Blödsinn. Denn das bringt ja nix. Einfach defaultwerte nehmen weil wir lustig sind ist sinnlos. Lieber auf ne ordentliche Reaktion vom User der Engine warten.

    otze schrieb:

    assert ist für mich im code unfindbar, wenn ich auf fehlersuche bin, ein try/catch block fällt mir sofort ins auge.

    Hä?

    Mein assert sagt mir immer die Zeile, die Datei und die Funktion in der es ausgelöst wurde.
    OK, meine Exceptions liefern mir auch einen Stack Trace - aber das ist doch kein Argument gegen assert.

    das Failbit gefällt mir übrigens garnicht. denn immer wenn ein Fehler nur irgendwo gemeldet wird, aber nicht aktiv auftritt (wie bei einer exception) kann man ihn viel zu leicht ignorieren.



  • asserts muss man eigentlich überhaupt nicht suchen. Die schreibt man und vergißt man. Es sei denn, sie schlagen an.



  • @Shade: Man kanns ja auch ignorieren, dass die Engine den Fullscreen-Modus nicht geschafft hat, jeder weiterer Engine-Aufruf tut halt nichts mehr, das wird sehr schnell ein Disaster...

    MfG SideWinder



  • SideWinder schrieb:

    @Shade: Man kanns ja auch ignorieren, dass die Engine den Fullscreen-Modus nicht geschafft hat, jeder weiterer Engine-Aufruf tut halt nichts mehr, das wird sehr schnell ein Disaster...

    eben. Deshalb sind exceptions besser. Denn die kann man nicht so einfach ignorieren. Dafür muss man nämlich ein

    catch(...){}
    schreiben - das fällt auf.

    aber etwas das nicht da ist (Fehlerbehandlung) fällt nicht so leicht auf.



  • Dann habe ich aber wieder diese vielen catch-Blöcke, und imho entspricht es mehr der OOP-Logik, dass ein Objekt seinen Zustand verwaltet und nicht jemand anderen die Botschaft schickt "Hilfe, mach was!"

    Und auf Grund der Unübersichtlichkeit auf try/catch zu verzichten obwohl die Methode eine Exception werfen kann ist auch nicht das Gelbe vom Ei.

    Wenn die Größe natürlich zur CompileTime feststeht dann brauch ich nur beim ersten Mal try/catch.

    if(x!=800 && y !=600)
        throw;
    
    ...
    
    setres(800,600); // da brauch ich keinen try/catch mehr wenn ich weiß wann setres Exceptions wirft
    

    Aber ansonsten ist es eine grobe Fahrlässigkeit.

    Damit man diese Compiletime-Konstanten sofort auswerten kann gibts bereits ne Mailingliste dazu lang1@coollist.com , soll auf jeden Fall mit aufgenommen werden 😉

    [Das Plenken war Absicht...]

    MfG SideWinder



  • godlikebot schrieb:

    Shade of Mine schrieb:

    Eben nicht.
    Wieso sollte man soetwas schreiben?

    try
    {
        WasProbieren();
    }
    catch(...)
    {
        Reagieren();
    }
    
    try
    {
        WasAnderesProbieren();
    }
    catch(...)
    {
        AuchDaraufReagieren();
    }
    Und so weiter
    

    Kann man denn sagen, dass C-Style Fehlerbehandlung in C++ schlechterer Stil ist als Exceptions?

    Also mit Exceptions ist die Fehlerbehandlung IMHO erheblich einfacher (Mit entsprechenden Werkzeugen ➡ RAII / ScopeGuard ⚠ ). Normalerweise müsstest du eigentlich den Rückgabewert von praktisch jeder Funktion prüfen. Das ist a) lästig und b) ziemlich fehleranfällig, auch weil es in verschiedenen Bibliotheken jeweils anders gehandhabt wird (mal über Rückgabewert, mal errno, mal GetLastError). Da schreibe ich lieber meine Funktionen und werfe Exceptions. Der Aufrufer kann dann entscheiden, ob er es nochmal probieren will oder doch lieber den Vorgang abbricht und eine passende Fehlermeldung ausgibt.

    void BenutzerHatButtonGeklickt()
    {
    try
    {
        WasProbieren();
        WasAnderesProbieren();
    }
    catch(const std::exception& e)
    {
        HatLeiderNichtGeklapptWeil(e.what());
    }
    }
    


  • SideWinder schrieb:

    Dann habe ich aber wieder diese vielen catch-Blöcke, und imho entspricht es mehr der OOP-Logik, dass ein Objekt seinen Zustand verwaltet und nicht jemand anderen die Botschaft schickt "Hilfe, mach was!"

    Das Single-Responsibility-Principle steht dem entgegen. Ausserdem sind Exceptions sowieso für Fälle gedacht, in denen der Fehler nicht lokal behandelt werden kann. Das ist IMHO unabhängig von Stilfragen.



  • Aber du vergisst die Code-Übersichtlichkeit:

    // Ein...
    if(!setres())
        output_err(FATAL_ERROR,"Couldn't set resolution.",__FILE__,__LINE__);
    
    // ...ist sicherlich übersichtlicher als:
    try
    {
        setres();
    }
    catch(error& obj)
    {
        output_err(FATAL_ERROR,obj.what(),__FILE__,__LINE__-4);
    }
    

    Beinem vielleicht noch nicht, aber ab 10 untereinander wirds problematisch. Das obj.what() bringts halt noch zur detaillierteren Beschreibung des Fehlers (nun darf die Funktion ja dran - eine nicht gefundene Datei die zum Setzen der res benötigt wird, wird nicht plötzlich zu einem Grafikfehler...).

    MfG SideWinder



  • Warum hat man sowas eigentlich nicht eingeführt:

    // rückgabetyp name (params) : (exception_params)
    
    typ setres (int x, int y) : (const std::string&)
    {
        typ ret_data; // also rückgabewert benützen wir, keine status-meldung möglich
    
        if(x!=800 && x!=1024)
            warning("X is not a standard-value"); // string da std::string
    
        if(FAILED(Interface->SetScreenResolution(x,y)))
            error("can't set res"); // string da std::string
    
        return(ret_data);
    
        warning // Interne Reaktion
        {
             // Mach was bei Warnungen
             // Bevor das Schlüsselwort zählt impliziter aufruf von externer reaktion
             continue; // Weitermachen oben, andere Möglichkeit wäre throw
        }
    
        error
        {
             // Mach was bei Errors
             throw; // da fatal error
        }
    }
    

    Zudem kann der Aufrufer noch folgendes machen:

    void output_err (const std::string& bla) // da func ja std::string übernimmt
    {
        MessageBox(...);
    }
    
    void output_fatalerr (const std::string& bla) // dito
    {
        MessageBox(...);
        exit(-1);
    }
    
    func(1023,768) : warning(output_err), error(output_fatalerr);
    

    Oder so etwas in diese Richtung. Gibts da Probleme damit? Ansonsten schlag ich das für lang1 vor.

    MfG SideWinder



  • übersicht!

    du springst ja wirr herum.

    wie willst du auf ne warnung reagieren? entweder ist es ein fehler oder nicht. wenn es ein fehler ist, dann behandle oder wirf ihn. wenn es eine warnung ist, dann logge oder ignoriere sie.

    da brauch ich kein 'catch'...
    denn du hast im prinzip ein goto mit dynamischen labels gemacht.

    bzw: tut es hier eine funktion warning() vermutlich auch...


Anmelden zum Antworten