Fehlerbehandlung in einer Engine



  • Verstehe ich nicht. Wo ist der Unterschied zu Exceptions?

    q.e.d 😃



  • knivil schrieb:

    Die Ressource weiss, das sie geladen wurde oder nicht geldaen wurde. Ist 'nen Objekt und zustandsbehaftet. Sie weiss es einfach. Z.B. bool Texture.load(...) legt Speicher an kopiert Texturdaten rein. Naja, ist was fehlgeschlagen, dann ist der Speicherpointer halt 0. Lade ich jetzt meine 10 Texturen wird nur im Erfolgsfall kopiert, smart_ptr whatever ... . Falls nicht, wird der Destruktor der Resourcen aufgerufen.

    Aufpassen.
    Es geht darum WANN der Dtor aufgerufen werden soll. Und das muss er manchmal eben sofort (rollback) und nicht später.

    Btw. ich weiss schon was es mit RAII, Gards etc. auf sich hat. Aber es ging ja um Exceptions. Wenn bool Texture.load( ... ) 'ne Exception werfen wuerde, dann waere ich gezwungen mittels try-catch diese zu fangen. Hier gebe ich einfach nur false zurueck. Soll der Benutzer der Funktion sich darum kuemmern. (Nein es ist nicht der Anwender, sondern der Programmierer, der meine Funktion benutzt, meist ich selber).

    Nein. exceptionsicherheit hat nichts aber auch rein garnichts mit try/catch zu tun.

    Schau dir mal die codes in meinem artikel an - wieviele try/catch siehst du? Im idealfall hast du exakt 1 try/catch in deinem programm.



  • Ich kenne den Unterschied zwischen exceptionsicher und und Exceptions. Aber ich sollte doch ein Beispiel fuer 10 Resourcen ohne Verwendung von Exceptions fuer Tachyon liefern ... dat isses. Ja wenn sofort ein Rollback durchgefuehrt werden soll, dann ... muss ich drueber nachdenken. In dem Artikel kommen sehr wenig try/catch vor, aber ich bin da noch von dem anderen Artikel gepraegt ...

    Verstehe ich nicht. Wo ist der Unterschied zu Exceptions?

    Ich benutze keine und zwinge den Benutzer/Programmierer nicht dazu, welche zu benutzen. Wenn er dann eine Exception basierend auf der Rueckgabe werfen moechte, kann er gern machen.



  • knivil schrieb:

    Aber ich sollte doch ein Beispiel fuer 10 Resourcen ohne Verwendung von Exceptions fuer Tachyon liefern ...

    Dein Beispiel funktioniert aber nicht, bzw. macht keinen Sinn.



  • knivil schrieb:

    aber ich bin da noch von dem anderen Artikel gepraegt ...

    Dann wird es Zeit dass du dir modernes Exceptionhandling ansiehst und mir Gründe nennst warum error Codes besser sind.

    Vorallem solltest du mal darüber meditieren:

    Es gibt 3 Probleme mit diesem Code.

    1. Die Fehlerbehandlung erfolgt lokal und macht dadurch den Code schwerer lesbar.
    2. Jede Funktion verlangt andere Behandlung von Fehlern.
    3. In Sprachen ohne Garbage-Collector muss man seinen eigenen Mist selbst wegräumen. Dieser Cleanup-Code ist kompliziert einzubauen. Hier z.B. über hässliche gotos gelöst. Alternativ auch mit tief verschachtelten ifs lösba

    Punkt 3 ist mit RAII lösbar, aber Punkt 1 und 2 liegen schwer.



  • What the fuck ? So (aehnlich) arbeite ich staendig. Ich muss zugeben, dass ich mir nicht die Muehe gemacht habe ein schoen formatiertes Beispiel mit C++ Syntax zu basteln. Sorry.

    Error Codes besser/schlechter ... das ist so eine Ansichtssache. Ich finde Exceptions restriktiver. Mom, ich suche mal nen Zitat ... finde es grad nicht, sorry



  • knivil schrieb:

    Ich finde Exceptions restriktiver

    Gründe bitte.



  • Ich zwinge den Benutzer meiner Funktion auch Exceptions zu benutzen. Er kann nicht auf Exceptions verzichten.



  • knivil schrieb:

    Ich zwinge den Benutzer meiner Funktion auch Exceptions zu benutzen. Er kann nicht auf Exceptions verzichten.

    Und die Alternative: Erzwingen lokaler Fehlerbehandlung durch das Verwenden von Error-Codes findest du weniger restriktiv?



  • Helferlein, Ein schrieb:

    knivil schrieb:

    Ich zwinge den Benutzer meiner Funktion auch Exceptions zu benutzen. Er kann nicht auf Exceptions verzichten.

    Und die Alternative: Erzwingen lokaler Fehlerbehandlung durch das Verwenden von Error-Codes findest du weniger restriktiv?

    knivil, dabei könntest du es dir doch so einfach machen. Es gibt nämlich ein Argument gegen Exceptions und für Error-Codes. Ich gehe soweit und sage sogar es ist das Argument gegen Exceptions.



  • knivil schrieb:

    Ich zwinge den Benutzer meiner Funktion auch Exceptions zu benutzen. Er kann nicht auf Exceptions verzichten.

    Genauso zwingst du den Benutzer deiner Funktion lokal auf die Fehler zu reagieren. Er kann nicht auf error codes verzichten.

    Deshalb: sag mal n ordentliches argument gegen exceptions



  • Helferlein, Ein schrieb:

    Und die Alternative: Erzwingen lokaler Fehlerbehandlung durch das Verwenden von Error-Codes findest du weniger restriktiv?

    Soll er doch ne Exception werfen basierend auf den Fehlercode. Prinzipiell habe ich nichts gegen Exceptions, nur werden sie haeufig an falscher Stelle eingesetzt.

    Ich soll 's mir so einfach machen? Hoert auf mich zu noetigen und Generalisieren werde ich nicht! Exceptions ueber Bibliotheksgrenzen hinweg sind einfach scheisse und alles was damit zusammenhaengt. Aber das 'nen generelles Problem von C++.



  • Da is man mal ne Studne nicht da und hat gleich richtig was zu lesen.

    Shade Of Mine schrieb:

    if(!InitDevice()) {
      return ID_FAILED;
    }
    if(!SetupScene()) {
      return SS_FAILED;
    }
    if(!RunLoop()) {
      return RL_FAILED;
    }
    

    versus

    InitDevice();
    SetupScene();
    RunLoop();
    

    Ich habe jetzt mal den Code zusammenkopiert. Zum oberen Teil, was wäre dann dem If so evrwerflich? man sieht auf einen Blick was Sache ist und was passiertw enn was passiert, option nr2 ohne die Ifs steht einem ja auch noch offen wenn man sich 100% sicher ist das es so klappen kann.

    Shade Of Mine schrieb:

    class Class { 
    private: 
      char* name; 
      int* array; 
    
    public: 
      Class(char const* name) 
      : name(0), array(0) 
      { 
        try { 
          this->name = new char[strlen(name)+1]; 
          array = new int[100]; 
        } 
        catch(std::bad_alloc& e) { 
          delete [] this->name; 
          delete [] array; 
          throw; 
        } 
        strcpy(this->name, name); 
        fill(array); 
      } 
    //... 
    };
    

    Alternativ auch mit if/else und 0 statt bad_alloc vorstellbar.

    Aber dank exceptions kann ich daraus folgendes machen:

    class Class { 
    private: 
      std::string name; 
      std::vector<int> array; 
    
    public: 
      Class(char const* name) 
      : name(name), array(100) 
      { 
        fill(array); 
      } 
    //... 
    };
    

    Ja sowas im drehe meine ich das hab ich gelesen. Was ich an dem Beispiel auszusetzen hätte wäre das man das selbe was da ind em Try Block und dem Katch passiert auch über ne einafche if Abfrage lösen könnte, ich meine es klappt doer nicht und die Variante if und errorcode würde das selbe bewirken, der Anwender könnte ja genauso abfragen obe r errrorcode geliefert wurde und dann an eine Funktion verweisen die das Problem beseitigt, damit wäre dann die Fehlerbehandlung auch ausgelagert. Teil 2 erschließt sich mir nicht wo sind denn da die Exceptions?

    Mir fehlt nachwievor ein guter Grund die sachen einzusetzen, ich habe hier zB gerade ein Gedankenspiel, ich habe einen Texturmanager der Texturen lädt und verwaltet. Wenn eine Textur nicht geladen werden kann kann ich genauso einen errorcode abgeben der sagt das teil kontne nicht geladen werden, was der Nutzer damit macht wäre ja egal, ich sehe da in Exceptions keinen Vorteil, nur den Nschteil das ich sie nicht ignorieren darf. Eine Ordliche fehlerbehandlung müsste ich auch nichtmal durchführen, denn in dem Moment wo mir ein Errorcode entgegen komtm kann ich genauso auf eine Funktion verweisen die zB eine Standarttextur lädt die für diesen Fall vorgesehen ist, das geht mit Exceptions genauso, sie liefern mir also Gedanklich keinen vorteil, nur Nachteile weil ich die Ifs bedeutend Lesbarer finde.



  • knivil schrieb:

    Helferlein, Ein schrieb:

    Und die Alternative: Erzwingen lokaler Fehlerbehandlung durch das Verwenden von Error-Codes findest du weniger restriktiv?

    Soll er doch ne Exception werfen basierend auf den Fehlercode. Prinzipiell habe ich nichts gegen Exceptions, nur werden sie haeufig an falscher Stelle eingesetzt.

    Ich soll 's mir so einfach machen? Hoert auf mich zu noetigen und Generalisieren werde ich nicht! Exceptions ueber Bibliotheksgrenzen hinweg sind einfach scheisse und alles was damit zusammenhaengt. Aber das 'nen generelles Problem von C++.

    Aber das gleiche kann er doch auch mit den Exceptions tun, einfach Fangen und dafür einen Fehlercode zurückgeben.

    Mit deinem letzten Satz bist du dem Argument von dem ich weiter oben sprach schon recht nahe, aber noch nicht ganz.



  • Aber das gleiche kann er doch auch mit den Exceptions tun, einfach Fangen und dafür einen Fehlercode zurückgeben.

    Ja genau, der keinen Exceptioncode schreiben moechte, muss es trotzdem tun ... Und anfangen zu raten werde ich hier bestimmt nicht.



  • knivil schrieb:

    Aber das gleiche kann er doch auch mit den Exceptions tun, einfach Fangen und dafür einen Fehlercode zurückgeben.

    Ja genau, der keinen Exceptioncode schreiben moechte, muss es trotzdem tun ... Und anfangen zu raten werde ich hier bestimmt nicht.

    Ja genau, der keinen Error-Code-Quellcode schreiben moechte, muss es trotzdem tun ...

    Das führt doch zu nichts. Aber wie gesagt es gibt einen Grund warum der Einsatz von Error-Codes besser sein kann: wenn die Bibliothek nicht ausschließlich für C++ gedacht ist.


  • Administrator

    @knivil,
    Ok, vielleicht mal ein paar einfachere Argumente, wieso ich mich gegen Fehlercodes entschieden habe:
    1. Was passiert wenn ein Fehler ignoriert wird:
    Bei der Exception, fliegt sie durch, das Programm wird terminniert.
    Beim Fehlercode, läuft das Programm weiter, bis irgendwo wahrscheinlich ein fataler Fehler auftritt und das Programm heftig abstürzt, womöglich aber vorher noch Daten korumpiert.
    2. Was passiert, wenn man mit verschiedenen Bibliotheken in einer stark verschachtelten Funktionskette arbeitet. Man möchte am Ende der Kette erfahren, was für ein Fehler auftrat:
    Bei Exceptions, müssen einfach nur alle möglichen Exception zuoberst über einen try-catch Block gefangen werden. Perfekt.
    Bei Fehlercodes, muss man nicht nur eine Übereinstimmung der Datentypen haben, sondern dann auch noch irgendwie erfahren, von welcher Bibliothek nun der Fehlercode kam, denn wahrscheinlich ist der Wert, der jeweiligen Fehlercodes noch identisch. Ergo, ich kann es nicht mehr herausfinden. Ich muss aufeinmal an die Funktionen Objekte mitgeben, welche die Fehler mitloggen sollen. Die Funktionen machen dadurch nicht nur Dinge, welche sie eigentlich gar nichts angeht, sondern sie werden auch noch aufgeblasen und komplex zu lesen.

    Zudem möchte ich mich noch selber zitieren:

    Dravere schrieb:

    Wenn man trotzdem Fehlercodes anbieten möchte, dann schlage ich eine Überladung der Funktion vor, wo man eine Variable übergeben kann, wo dann der Fehlercode reingespeichert wird. Die Funktion hat dann eine nothrow Garantie.

    Oder vielleicht das ganze in Code:

    void foo(); // Kann eine Exception werfen
    
    void foo(myengine::ErrorCode& errCode)
    {
      try
      {
        foo();
        errCode = myengine::NO_ERR;
      }
      catch(myengine::Exception& err)
      {
        errCode = err.get_code();
      }
    }
    

    Typisches Beispiel für so eine Schnittstelle, findet man bei Boost.Asio.

    Grüssli



  • zu 1) Du hast einen lausigen Programmierer.
    zu 2) In die Logdatei schauen. Ich wuerde keine inout-Parameter einer Funktion fuer Fehleridentifizierung mitgeben. Desweiteren kann der Fehlerort mit Exceptions nicht eindeutig bestimmt werden. Was hilft dir ein out_of_range Exception?

    Fehler sollten entweder durch Exceptions oder "Fehlercodes" gehandhabt werden, ein Mischmasch halte ich nicht fuer sinnvoll.



  • Dravere schrieb:

    Ok, vielleicht mal ein paar einfachere Argumente, wieso ich mich gegen Fehlercodes entschieden habe:
    1. Was passiert wenn ein Fehler ignoriert wird:
    Bei der Exception, fliegt sie durch, das Programm wird terminniert.
    Beim Fehlercode, läuft das Programm weiter, bis irgendwo wahrscheinlich ein fataler Fehler auftritt und das Programm heftig abstürzt, womöglich aber vorher noch Daten korumpiert.

    Und was ist wenn die Exception einafch durch einen fehelr oder Unwissenheit des Benutzers nicht abgefangen wurde? Dann crasht das Programm trotzdem.

    Dravere schrieb:

    2. Was passiert, wenn man mit verschiedenen Bibliotheken in einer stark verschachtelten Funktionskette arbeitet. Man möchte am Ende der Kette erfahren, was für ein Fehler auftrat:
    Bei Exceptions, müssen einfach nur alle möglichen Exception zuoberst über einen try-catch Block gefangen werden. Perfekt.
    Bei Fehlercodes, muss man nicht nur eine Übereinstimmung der Datentypen haben, sondern dann auch noch irgendwie erfahren, von welcher Bibliothek nun der Fehlercode kam, denn wahrscheinlich ist der Wert, der jeweiligen Fehlercodes noch identisch. Ergo, ich kann es nicht mehr herausfinden. Ich muss aufeinmal an die Funktionen Objekte mitgeben, welche die Fehler mitloggen sollen. Die Funktionen machen dadurch nicht nur Dinge, welche sie eigentlich gar nichts angeht, sondern sie werden auch noch aufgeblasen und komplex zu lesen.

    Logbuchfunktion, ein Funktionsaufruf mit etwas Text der in ein Logbuch egschrieben wird, fertig, dann kann man hinterher nachschaun wo das Problem genau lag und kann sogar noch richtig viele Informationen drin zurücklassen. Was nützt es denn wenn man ne Kette aus 20 Funktionen hat und am ende erfährt das die Funktion nr10 absolut in die Hose ging? Wenn die Funktion zB Teile aus eienr Datei laden soltle dann wäre das Ladend er Datei fehlgeschlagen, ob es an diesem teil lag wäre nebensächlichd enn auch das wissen wo genau es geschah im Programm würde dir ja im Zweifel nicht unbedingt weiterhelfen, mehr als ein Daten Korrupt könntest du nicht ausgeben, da wäre die Exception im Grudne genauso aussagefähig wie ein errorcode der einfach sagt Fehler beim lesend er datei und ein Logbuch hilft dir am Ende ja eh mehr weil du darin genau siehst was sache war.



  • knivil schrieb:

    Fehler sollten entweder durch Exceptions oder "Fehlercodes" gehandhabt werden, ein Mischmasch halte ich nicht fuer sinnvoll.

    👍

    knivil schrieb:

    Was hilft dir ein out_of_range Exception?

    Imho nichts, solche Sachen sollten meiner Meinung nach durch asserts geregelt werden (also Fehler, die nicht auftreten dürften). Eine FileNotFoundException nützt aber schon eher 🙂

    Xebov schrieb:

    Und was ist wenn die Exception einafch durch einen fehelr oder Unwissenheit des Benutzers nicht abgefangen wurde? Dann crasht das Programm trotzdem.

    Was gut ist! Nichts ist schlimmer als unbemerkte Fehler.


Anmelden zum Antworten