Exception oder Rückgabewert?



  • hmm, lass mich überlegen...wenn eine Funktion bereits einen Wert returnen soll, muss ich einen Fehler anderweitig bemerkbar machen...

    Exceptions für Marginales wie File-EOF oder Zeugs benutze ich nicht, sondern wirklich nur für Fehler, die das Programm nicht mehr fortfahren lassen können.



  • Auf jeden Fall nur für "richtige" Fehler, bwz. für Sonderfälle wie Konstruktoren oder festgelegte Funktionsschnittstellen, überladene Operatoren oder redefinierte Funktionen...



  • Hallo

    Rückgabewerte für Fehler, wenn der Fehler im weiteren Verlauf behoben werden kann.

    Exceptions für Fehler, die zwar bestimmbar sind, aber auf jeden Fall zum geordneten Abbruch des Programms führen sollen

    asserts für alle unerwarteten Fehler, nach denen es einfachen nicht weiter gehen kann

    bis bald
    akari



  • Exceptions sind aber nicht langsamer. Ganz im Gegenteil, bei Return-Werten machst du immer einer if-Abfrage, selbst wenn kein Fehler auftritt. Bei Exceptions kommst du in den catch-Block, nur wenn ein Fehler auftritt. Wenn kein Fehler auftritt, geht es ganz normal weiter im Programm. Das werfen einer Exception ist aber performancemäßig also völlig vertretbar.

    Es gibt ja mehrere Exception-Kategorien. Z.B. Resourcen-Fehler (Drucker nicht ansprechbar) sollte man mit einer Exception weiter werfen. Benutzerfehler, z.B. eine falsch eingegebene PIN beim Geldautomaten, sollte man nicht als Exception werfen. Denn es ist ja kein unerwarteter Ausnahmefehler! Aber das ein Drucker auf einmal nicht ansprechbar ist, sollte man als "unerwartet" einordnen. OK, dann gibts halt noch Logicfehler, die man auch als Exceptions wirft. Laufzeitfehler werden eh autom. geworfen.

    Exceptions haben außerdem noch den Vorteil, das man sie weiter reichen kann, wenn man selber nicht weiß, wie man auf einen Fehler regieren muß. Wie soll das bei einem Return-Wert vernünftig funktionieren? Da weiß doch am Ende niemand, was eigentlich falsch lief.

    An Performance würde ich nicht meine Gedanken verschwenden, wenn es um Exceptions geht. Dafür relativiert sich nämlich alles wieder, was die Mächtigkeit von Exceptions angeht. Und Exceptions benötigen nur dann Performance, wenn sie wirklich geworfen werden. Wenn keine Fehler auftauchen, ist es sogar letztendlich schneller als eine if-Abfrage bei einem Return-Wert!



  • Artchi schrieb:

    Wenn kein Fehler auftritt, geht es ganz normal weiter im Programm. Das werfen einer Exception ist aber performancemäßig also völlig vertretbar.

    Ne, das werfen ist verdammt lahm - nur das nicht werfen ist verdammt schnell 😉
    Und in einem erfolgreichen Programmdurchlauf fliegt idR keine Exception - man ist also idR mit Exception sogar schneller als ohne 🙂

    Denn es ist ja kein unerwarteter Ausnahmefehler!

    Genau das bringt es auf den Punkt -> Exception sind Ausnahmen 👍

    OK, dann gibts halt noch Logicfehler, die man auch als Exceptions wirft.

    Ich werfe idR nie einen std::logic_error - ich mache da eigentlich immer ein ASSERT()

    Exceptions haben außerdem noch den Vorteil, das man sie weiter reichen kann, wenn man selber nicht weiß, wie man auf einen Fehler regieren muß.

    Noch ein wichtiger Punkt 👍
    Exception erlauben das behandeln dort wo es Sinn macht und nicht dort wo der Fehler auftrat.

    Und Exceptions benötigen nur dann Performance, wenn sie wirklich geworfen werden.

    Leider nicht - stack unwinding code ist nicht gratis 😞 aber allemale billiger als 5 if (die ja alle bedingte sprünge beinhaltet -> goto ist böse :p)

    Wenn keine Fehler auftauchen, ist es sogar letztendlich schneller als eine if-Abfrage bei einem Return-Wert!

    Full ACK
    mal davon abgesehen, dass man return Werte gerne ignoriert 😉 um eine Exception zu ignorieren muss man schon explizit catch(...){} schreiben. Und sowas fällt beim Code-Review dann auf, und man kann dem Programmierer dann eine auf die Finger geben 😉



  • Exceptions für Fehler, die zwar bestimmbar sind, aber auf jeden Fall zum geordneten Abbruch des Programms führen sollen

    Nein. Woher nimmst du diese Weisheit bitte?



  • ich nehm exceptions am liebsten in solchen fällen

    func()
    {
      //funcinit
    
      //mach was  
      if ( fehler )
      {
        //funcdeinit
        //return
      }
      //mach was  
      if ( fehler )
      {
        //funcdeinit
        //return
      }
      //mach was  
      if ( fehler )
      {
        //funcdeinit
        //return
      }
      //funcdeinit
      //return
    }
    
    func()
    {
      //funcinit
      try()
      {
        //mach was  
        if ( fehler )
          throw;
        //mach was  
        if ( fehler )
          throw;
        //mach was  
        if ( fehler )
          throw;
      }
      catch()
      {
      }
      //funcdeinit
      //return
    }
    

    gutes beispiel is wenn man z.b. ne datei aufmacht oder speicher allokiert



  • Sovok schrieb:

    gutes beispiel is wenn man z.b. ne datei aufmacht oder speicher allokiert

    Bitte sag, dass das nicht dein ernst ist.

    da kann man ja gleich nur die return werte auslesen...



  • ich benutz es in dem fall nich um returnwerte nicht auslesen zu müssen, sondern um zeilen zu sparn

    die einzige alternative die mir in dem fall einfällt is goto aber des benutz ich aus prinzip ned



  • .
    Noch ein wichtiger Punkt 👍
    Exception erlauben das behandeln dort wo es Sinn macht und nicht dort wo der Fehler auftrat.

    das ist einerseits richtig, aber in 80% der fälle können fehler vor ort gelöst werden,und da hab ich persönlich doch eher ein if, in dem ich dann selber ne exception schmeissen kann, wenns wirklich nicht mehr an der stelle weitergehen kann. das problem an ner exception ist ja, dass man nicht mehr zurück in den code springen kann, wenn der fehler gelöst wurde, das macht diese ausnahmebehandlung nochmal teurer.



  • Hallo

    Exceptions für Fehler, die zwar bestimmbar sind, aber auf jeden Fall zum geordneten Abbruch des Programms führen sollen

    Nein. Woher nimmst du diese Weisheit bitte?

    zum Beispiel wenn eine externe Datei, ein Registry-Schlüssel oder ein Server nicht erreichbar ist. Dann kann ich eine auch für den User sinnvolle Fehlermeldung ausgeben und das Programm auf jeden Fall beenden (wenn übergreifende try-Behandlung gibt)

    Mit nicht bestimmbar meine ich, wenn eine Funktion mit

    int foo(TClass *Class)
    

    mit Class == NULL aufgerufen wird, obwohl ein solcher Wert gar nicht verarbeitet werden kann.

    bis bald
    akari



  • Dafür nimmt man dann assert.



  • akari schrieb:

    Hallo

    Mit nicht bestimmbar meine ich, wenn eine Funktion mit

    int foo(TClass *Class)
    

    mit Class == NULL aufgerufen wird, obwohl ein solcher Wert gar nicht verarbeitet werden kann.

    bis bald
    akari

    das is meiner meinung nach der job von nem assert weil der input vom programmierer kommt und der programmierer sicherzustellen hat, dass er keine null pointer übergibt

    int foo(TClass *Class)
    {
      assert ( Class != NULL );
    }
    

    in der theorie könnte sich der übergabewert im debug und release modus unterscheiden falls dem system der speicher ausgeht

    in der praxis gibts keinen unterschied wenns keine speicherintensive anwendung is



  • Shade Of Mine schrieb:

    Sovok schrieb:

    gutes beispiel is wenn man z.b. ne datei aufmacht oder speicher allokiert

    Bitte sag, dass das nicht dein ernst ist.
    da kann man ja gleich nur die return werte auslesen...

    wieso sollte man das nicht so machen? das problem ist ja, das alle standart-libs statt exception return wert liefern. ( auser der STL vieleicht )
    ich benutzt exceptions häufig um das HRESULT aus directx auszuwerten. eine einzige exception-klasse die zu dem HRESULT einen info-text ausgibt. und in der winmain steht dann ein try catch mit fehlerdialog im catch block.



  • Hallo

    Dafür nimmt man dann assert.

    Exakt. Das habe ich auch in meinem ersten Post so dargestellt, habe es nur in der Erläuterung vergessen zu erwähnen.

    bis bald
    akari



  • DEvent schrieb:

    wieso sollte man das nicht so machen? das problem ist ja, das alle stan****-libs statt exception return wert liefern. ( auser der STL vieleicht )

    bei den IOStreams kann man exceptions einschalten und C Libraries wrappt man.
    Und die anderen C++ Standard Funktionen können kaum fehlschlagen...

    wenn man
    if(foo()) throw;
    if(foo2()) throw;
    schreibt, dann kann man sich exceptions ja gleich sparen - sie bringen hier nur verdammt wenig.

    ein
    foo();
    foo2();
    ist hier viel schöner und eleganter (zudem kann man auch noch bessere exception werfen, weil man GetLastError()/errno oder sonstwas auswerten kann...



  • Merkregel: Fasse nie eine C-API roh an. 🤡 🤡 Wrap it up! 👍



  • Sovok schrieb:

    ich benutz es in dem fall nich um returnwerte nicht auslesen zu müssen, sondern um zeilen zu sparn

    die einzige alternative die mir in dem fall einfällt is goto aber des benutz ich aus prinzip ned

    Ja ganz toll: Exceptions als Ersatz für das (teilweise zu Recht) verpönte goto zu benutzen... 🙄



  • Prüft ihr pointer generell mit Assert? Ich prüfe diese immer, wenn sie NULL sein können mit nem einfachen if (!p) /*mach irgendwas*/ und Asserts verwende ich nur zum prüfen von Arraygrenzen usw. oder wenn nen Zeiger wirklich niemals NULL sein kann.

    Exceptions verwende ich dann wenn es Sinn macht z.B. wenn der Rückgabewert kein Fehlercode ist sondern ein Wert, oder wenn es wirklich eine Ausnahme ist, z.B. wenn die Rechte für eine Operation fehlen.



  • MaSTaH schrieb:

    Sovok schrieb:

    ich benutz es in dem fall nich um returnwerte nicht auslesen zu müssen, sondern um zeilen zu sparn

    die einzige alternative die mir in dem fall einfällt is goto aber des benutz ich aus prinzip ned

    Ja ganz toll: Exceptions als Ersatz für das (teilweise zu Recht) verpönte goto zu benutzen... 🙄

    ne der wesentliche unterschied is, dass man per goto überall hinspringen kann wohingegen die exception zum ende des try blocks springt
    find ich wesentlich definierter

    aber gehen wir mal zum spass von ner speicherintensiven anwendung aus bei der keine exceptions benutzt werden dürfen

    char* p1=NULL,p2=NULL,p3=NULL;
    
    //mach was
    p1 = new char[/*variabel*/];
    if ( p1 == NULL )
      //return
    //mach was
    p2 = new char[/*variabel*/];
    if ( p1 == NULL )
      //return
    //mach was
    p3 = new char[/*variabel*/];
    if ( p1 == NULL )
      //return
    

    wie würdest du hier am besten sicherstellen, dass aufgeräumt wird und gleichzeitig redundanten code vermeiden?


Anmelden zum Antworten