Frage zu return-Ergebnissen



  • Programmierst du mit C++? Dann hast du dort die wunderschöne Möglichkeit Exceptions zu verwenden, oder in Situationen die weniger schlimm sind auch mal einen Status für das Objekt setzen (wie bspw. die Status-Bits in der iostream-Library).

    Falls du Java/C# programmierst nimm für alle auftretenden Fehler Exceptions.

    MfG SideWinder



  • Anfänger1 schrieb:

    Ich wollte mal wissen wie ihr das mit Funktionsrückgabewerten handhabt...

    Ich: Wenn es wirkliche Fehler sind => Exception. Sonst return-Wert (mit der Gefahr die Prüfung zu vergessen).



  • Wie macht ihr das wenn innerhalb einer klasse ein fehler auftritt?
    da ich es lieber habe wenn arbeit und ausgabe getrennt sind dachte ich an eine externe funktion an die der Fehler übergeben wird... oder gibt es da andere/schönere varianten

    Ich bin mir nicht sicher ob ich dich richtig verstehe.

    Meinst du, dass der Code in der Klasse direkt eine EsIstEinFehlerAufgetreten(fehlerCode) Funktion aufruft? Also so...

    void HandleError(int errorCode);
    
    class Foo
    {
    public:
        void Bar()
        {
            // ... 
            if (something)
                HandleError(ERROR_SOMETHING);
        }
    };
    
    int main()
    {
        Foo foo;
        foo.Bar();
        return 0;
    }
    

    Das wäre schlecht, denn dadurch steckst du zwar die Fehlerbehandlung in eine eigene Funktion, aber koppelst die Klasse untrennbar an diese Funktion.

    Oder meinst du, dass die Funktionen der Klasse einen Fehlercode zurückgeben, den man dann ausserhalb der Klasse nimmt, und in die EsIstEinFehlerAufgetreten(fehlerCode) Funktion reinsteckt?

    void HandleError(int errorCode);
    
    class Foo
    {
    public:
        int Bar()
        {
            // ... 
            if (something)
                return ERROR_SOMETHING;
        }
    };
    
    int main()
    {
        Foo foo;
        int rc = foo.Bar();
        if (rc == 0)
            return 0; // alles in ordnung
        else
        {
            HandleError(rc);
            return 1; // FEEEEHLER
        }
    }
    

    Das wäre schonmal besser. Dadurch hast du den Teil wo der Fehler entsteht, und den Teil wo er behandelt wird wirklich entkoppelt.

    Noch viel besser finde ich die hier schon mehrfach erwähnten Exceptions.

    #include <stdexcept>
    
    void HandleError(int errorCode);
    
    class MyException : public std::runtime_error
    {
    public:
        MyException(int errorCode) :
            runtime_error("MyException"),
            m_errorCode(errorCode) 
        {
        }
    
        int GetErrorCode() const
        {
            return m_errorCode;
        }
    
    private:
        int m_errorCode;
    };
    
    class Foo
    {
    public:
        int Bar()
        {
            // ... 
            if (something)
                throw MyException(ERROR_SOMETHING);
        }
    };
    
    int main()
    {
        try
        {
            Foo foo;
            foo.Bar();
            return 0;
        }
        catch (MyException const& e)
        {
            HandleError(e.GetErrorCode());
            return 1;
        }
    }
    

    Vielleicht könntest du mal einfach ein Beispiel (kleinen Code-Schnippsel) posten, wie du dir das genau vorstellst. Dann könnte man besser darauf antworten.



  • Ich programmiere in C++
    Ich meinte eher sowas:

    class foo
    {
        public:
        foo(void (*errorfct)(int))
        {
            myerrorhandler = errorfct; 
        }
    
        bool mitrueckgabe( /*irgendwas*/)
        {
            if(/*Fehler*/)
            {
                myerrorhandler(fehlercode);
                // oder besser return false; ??
            }
        }
    
        void ohnerueckgabe (/*irgendwas*/) //zb. ein thread innerhalb einer Klasse
        {
            //tuwas
            myerrorhandler(fehlercode);
        }
        private:
        void (*myerrorhandler)(int);
    };
    
    void errorhandler(int code)
    {
        //mach was mit dem Fehler
    }
    
    int main(void)
    {
        foo myFoo(&errorhandler);
        //mach was
    }
    

    Ich hoffe man versteht was ich meine;

    Exceptions zu verwenden wäre in meinem Fall nicht so gut da das Problem mit einem Neustart eines Threads gelöst werden könnte;

    Ich hätte die oben verwendete Funktion vielleicht noch um ein short priority ergänzt und als Log verwendet, oder ist das eher ein no-go?



  • Ok.
    Also erstmal würde ich hier ein Interface statt einem Funktionszeiger verwenden, auch wenn nur eine Funktion benötigt wird.

    Und dann verstehe ich nicht wie du das mit dem Thread meinst.
    Wo genau würde es Probleme geben wenn man mit Exceptions arbeiten würde?
    Mal abgesehen vom üblichen Problem das man mit Exceptions & Thread hat: dass man gefangene Exceptions (noch) nicht von einem Thread zu einem anderen weitergeben kann.



  • hustbaer schrieb:

    Wo genau würde es Probleme geben wenn man mit Exceptions arbeiten würde?

    Soweit ich das verstanden habe wird ein Programm nachdem eine Exception geworfen wird beendet.
    Und genau das kann ich nicht brauchen wenn der Fehler durch ein einfaches neustarten des Threads behoben werden kann.

    hustbaer schrieb:

    Ok.
    Also erstmal würde ich hier ein Interface statt einem Funktionszeiger verwenden, auch wenn nur eine Funktion benötigt wird.

    Sorry für die Frage, aber was meinst du mit Interface?

    LG



  • Anfänger1 schrieb:

    hustbaer schrieb:

    Wo genau würde es Probleme geben wenn man mit Exceptions arbeiten würde?

    Soweit ich das verstanden habe wird ein Programm nachdem eine Exception geworfen wird beendet.
    Und genau das kann ich nicht brauchen wenn der Fehler durch ein einfaches neustarten des Threads behoben werden kann.
    LG

    Nein, das Programm wird durch das Werfen einer Exception nicht beendet.
    Du kannst selber entscheidenn, ob das Programm weiterlaufen kann oder es beendet werden muss.

    try
    {
     DeineFunktion();
    }
    catch (DeineException& e)
    {
     BehebeProblem();
    
     if (KonnteProblemBehobenWerden != true)
     {
      exit(1); // Problem konnte nicht behoben werden; Programm wird beendet.
     }
    }
    

    Damit das vernünftig funktioniert, musst du die Exception an geeigneter Stelle fangen. Das Fangen in der Hauptfunktion wäre wohl zu spät.



  • man sollte bedenken dass exceptions sehr langsam sind.

    ich finde eine lib bzw funktion sollte mehr als nur fehler oder kein fehler anbieten. es mag zwar gut sein im kleinen diese ja-nein methoden zu nutzen, aber in grossen zusammenhaengen sollten libs trotz eigentlichen fehlers eine warning ausgeben, am ende einen error-code zurueckliefern, aber dennoch versuchen, sofern es moeglich ist, weiter zu arbeiten.

    Ansonsten ist es extrem anstrengend produktiv zu sein wenn immer irgendjemand meint eine exception werfen zu muessen, gerade in dingen in denen man selbst nicht viel mehr tun kann als auf andere zu warten, dass sie es beheben. Oft passieren diese kleinen fehler aus dem zusammenhang mit den anderen komponenten.



  • raps schrieb:

    man sollte bedenken dass exceptions sehr langsam sind.

    Das letzte was ich dazu gelesen hab war, dass eine Exception ca. so viel "kostet" wie ein Funktionsaufruf. Und sich im Fehlerfall sorgen um Performance zu machen dürfte in den meisten Fällen eher übertrieben sein.



  • DerKuchen schrieb:

    raps schrieb:

    man sollte bedenken dass exceptions sehr langsam sind.

    Das letzte was ich dazu gelesen hab war, dass eine Exception ca. so viel "kostet" wie ein Funktionsaufruf.

    eine geworfene exception kostet ca 10 bis 100 mal von einem funktionsaufruf,falls es einen funktionsaufruf ueberhaupt gibt, das haengt z.b. davon ab wie tief verschachtelt man ist und wieviele optimierungen wegfielen wegen try/catch bloecken.

    Und sich im Fehlerfall sorgen um Performance zu machen dürfte in den meisten Fällen eher übertrieben sein.

    wenn es ausreichend fehlerfaelle gibt, wird es langsam, z.B. dynamic_cast ueber ein vector von objects um welche von einem speziellen typ heraus zu fischen.



  • Wenn es ausreichend Fehlerfälle gibt, dann stimm am Software-Design irgendwas nicht.
    Aus dem Grund würde ich auch sagen: dass Exceptions - wenn sie geworfen werden - langsam sind, darf kein Grund sein, sie nicht zu verwenden.

    Sorry für die Frage, aber was meinst du mit Interface?

    Eine Klasse die nur virtual-pure Funktionen hat. Sowas:

    class MyErrorHandlingInterface
    {
    public:
        virtual void HandleSomeError(int errorCode) = 0;
    };
    


  • raps schrieb:

    man sollte bedenken dass exceptions sehr langsam sind.

    Deshalb 64Bit verwenden 🙂

    Siehe http://www.c-plusplus.net/forum/viewtopic-var-t-is-219865.html

    Die Performance im Fehlerfall ist komplett irrelevant. Denn wenn du exception wirfst wenn es sich um keinen Fehler handelt, hast du etwas falsch gemacht (zB dein dynamic_cast beispiel). Und wenn du dauernd fehler in der anwendung hast, dann ist die performance wohl eh erstmal uninteressant :p



  • hustbaer schrieb:

    Eine Klasse die nur virtual-pure Funktionen hat. Sowas:

    class MyErrorHandlingInterface
    {
    public:
        virtual void HandleSomeError(int errorCode) = 0;
    };
    

    Tut mir leid wenn ich nochmal blöd nachfragen muß, aber wie kann ich mir das vorsellen?
    Ich nehme an das meine Klasse in der ein Fehler auftreten kann von MyErrorHandlingInterface erben soll.
    Aber wie bekommt dann das Hauptprogramm mit ob ein Fehler passiert ist?
    Bzw. eine bessere Formulierung ist: Ich verwende ja einen Funktionszeiger um nicht alle Fehlerbehandlungsroutinen in jeder Klasse bei einer Änderung des Quellcodes anpassen zu müssen, sondern um das Ganze an einer Zentralen Stelle zu haben.
    Wie kann ich das bei deinem Vorschlag machen. (warum einen pure-virtual Funktion?)

    @rest:
    Das mit den Exceptions ist ein bisschen problematisch, da ich in meiner Klasse mehere Threads habe, und es anscheinend nicht möglich ist Exceptions weiterzugeben.

    hustbaer schrieb:

    dass man gefangene Exceptions (noch) nicht von einem Thread zu einem anderen weitergeben kann.

    Danke schonmal für die bisherige Hilfe

    LG



  • Nö, die Klasse in der Fehler auftreten können erbt nicht vom Interface, sondern du leitest die Klasse vom Interface ab, die den Fehler behandeln soll.



  • Anfänger1 schrieb:

    Das mit den Exceptions ist ein bisschen problematisch, da ich in meiner Klasse mehere Threads habe, und es anscheinend nicht möglich ist Exceptions weiterzugeben.

    Nein, ist kein bisschen Problematisch. Denn der Thread muss ja irgendwo enden und dann muss er irgendeine notification an den rest der anwendung abgeben. und genau hier setzt du mit exceptions an. Die exception wird hier gefangen und du gibst die entsprechende notification weiter.



  • Shade Of Mine schrieb:

    raps schrieb:

    man sollte bedenken dass exceptions sehr langsam sind.

    Deshalb 64Bit verwenden 🙂

    indem du den teufel gegen den belzebub tauscht, aenderst du nicht viel am overhead. hast halt wenig heavy weight statt viel lightweight work.

    Die Performance im Fehlerfall ist komplett irrelevant. Denn wenn du exception wirfst wenn es sich um keinen Fehler handelt, hast du etwas falsch gemacht (zB dein dynamic_cast beispiel). Und wenn du dauernd fehler in der anwendung hast, dann ist die performance wohl eh erstmal uninteressant :p

    Da stimme ich zu, deswegen sagte ich, dass man moeglichst weit ohne exception werfen kommen sollte und auch dinge die man als fehler ansehen koennte, als warning rausstreamt und trotzdem weitermacht. performance der anwendung ist die eine sache die mit exceptions leidet, performance der entwicklung die andere.

    Ich habe in einer umgebung mit ca 50leuten mit einer lib gearbeitet die sich sehr "OOP" schimpfte, natuerlich mit exceptions bei allen moeglichen dingen. Fehlte eine datei die man oeffnen wollte -> exception, format von etwas war falsch -> exception. objekttyp von etwas war falsch -> exception...
    das resultat davon war extreme unproduktivitaet, man fixte oft fehler fuer fehler bis man endlich arbeiten konnte (und die die nichts fixen konnten, warteten).

    die alternative mit der ich jetzt arbeite hat nicht eine exception die geworfen werden wuerde. fuer alles was schiefgeht gibt es fallbacks und die streamen in den log.
    Man koennte zwar meinen, dass sowas fehler verbirgt und anarchie-maessig laeuft, aber genau das gegenteil ist der fall. Die leute arbeiten sehr produktiv und jede warning wird beseitigt, die leute sind auch weniger gehemt weit mehr warnings zu streamen als man exceptions werfen wuerde, weil man weiss, dass es niemanden behindert, sondern eher hilft.

    ich finde exceptions sollte man wirklich nur schmeissen wenn man sich garnicht mehr anders zu helfen weiss, also nicht bei "errors", sondern wirklich bei blockierenden ereignissen. Passiert bei unserer lib nur vom system aus, z.b. access violation.
    In dem fall sollte man dann auch (wie bei java ueblich ;)), den kompletten callstack und wenn moeglich den memory dump ausgeben.
    Man sollte soviel informationen wie moeglich von einer exception erhalten, denn wie das wort schon sagt, ist es eine ausnahme, somit sollte sie eigentlich nie passieren und ist somit auch nur aufwendig reproduzierbar.

    my2cent 😉



  • raps schrieb:

    indem du den teufel gegen den belzebub tauscht, aenderst du nicht viel am overhead. hast halt wenig heavy weight statt viel lightweight work.

    Du reduzierst im 64bit modus den runtime overhead von exceptions wenn sie nicht fliegen auf quasi 0 - da du nur noch in einer map nachsehen musst was zu tun ist und der key der IP ist...

    dh, das bereits ein if zur fehlerbehandlung teurer waere als 1000 moegliche exceptions. viel besser wirds nicht mehr gehen. denn innerhalb der funktion muss, sofern es kein catch gibt, NICHTS gemacht werden, nada.

    Da stimme ich zu, deswegen sagte ich, dass man moeglichst weit ohne exception werfen kommen sollte und auch dinge die man als fehler ansehen koennte, als warning rausstreamt und trotzdem weitermacht. performance der anwendung ist die eine sache die mit exceptions leidet, performance der entwicklung die andere.

    was fuer fehler sind denn warnungen?

    Ich habe in einer umgebung mit ca 50leuten mit einer lib gearbeitet die sich sehr "OOP" schimpfte, natuerlich mit exceptions bei allen moeglichen dingen. Fehlte eine datei die man oeffnen wollte -> exception, format von etwas war falsch -> exception. objekttyp von etwas war falsch -> exception...
    das resultat davon war extreme unproduktivitaet, man fixte oft fehler fuer fehler bis man endlich arbeiten konnte (und die die nichts fixen konnten, warteten).

    Ja ich hab auch schon schlechten java und C code gesehen.
    ich hab sogar mal schlechten bf code gesehen O_o

    die alternative mit der ich jetzt arbeite hat nicht eine exception die geworfen werden wuerde. fuer alles was schiefgeht gibt es fallbacks und die streamen in den log.

    der user will eine datei speichern, du kannst sie aber nicht speichern weil platte voll ist.
    was dann?

    ich finde exceptions sollte man wirklich nur schmeissen wenn man sich garnicht mehr anders zu helfen weiss, also nicht bei "errors", sondern wirklich bei blockierenden ereignissen. Passiert bei unserer lib nur vom system aus, z.b. access violation.

    definiere bitte was du fuer unterschiedliche fehlertypen kennst.

    Ich kenne nur 2 Arten: fatale fehler (logik fehler) die nie auftreten duerfen (interne invarianten verletzt) -> assert. Dann kenne ich noch "normale" Fehler, wie eben zB festplatte voll (laufzeit fehler - koennen immer auftreten) und das wars. Was kennst du noch fuer Fehler? Am besten mit Beispiel.



  • Shade Of Mine schrieb:

    raps schrieb:

    indem du den teufel gegen den belzebub tauscht, aenderst du nicht viel am overhead. hast halt wenig heavy weight statt viel lightweight work.

    Du reduzierst im 64bit modus den runtime overhead von exceptions wenn sie nicht fliegen auf quasi 0 - da du nur noch in einer map nachsehen musst was zu tun ist und der key der IP ist...

    dh, das bereits ein if zur fehlerbehandlung teurer waere als 1000 moegliche exceptions. viel besser wirds nicht mehr gehen. denn innerhalb der funktion muss, sofern es kein catch gibt, NICHTS gemacht werden, nada.

    wir sind uns doch einig drueber dass wir die wahl zwischen if oder catch haben, oder? (klingt so als ob du sagst if waere langsam, aber catch muss man nicht einbauen).
    die if abfrage kostet dich weit weniger als ein catch block.

    Da stimme ich zu, deswegen sagte ich, dass man moeglichst weit ohne exception werfen kommen sollte und auch dinge die man als fehler ansehen koennte, als warning rausstreamt und trotzdem weitermacht. performance der anwendung ist die eine sache die mit exceptions leidet, performance der entwicklung die andere.

    was fuer fehler sind denn warnungen?

    ich meine nicht fehler==warnungen, ich meine fehler kann man behandeln und dann muss man nur noch eine warnung ausgeben.
    z.b.
    bilddatei nicht gefunden -> dummy bild
    config nicht gefunden -> default settings
    out of memory -> alte resourcen freigeben und nochmal versuchen
    sound dll nicht geladen -> dummy interface zurueckgeben
    etc.

    Ich habe in einer umgebung mit ca 50leuten mit einer lib gearbeitet die sich sehr "OOP" schimpfte, natuerlich mit exceptions bei allen moeglichen dingen. Fehlte eine datei die man oeffnen wollte -> exception, format von etwas war falsch -> exception. objekttyp von etwas war falsch -> exception...
    das resultat davon war extreme unproduktivitaet, man fixte oft fehler fuer fehler bis man endlich arbeiten konnte (und die die nichts fixen konnten, warteten).

    Ja ich hab auch schon schlechten java und C code gesehen.
    ich hab sogar mal schlechten bf code gesehen O_o

    ich spreche eher von der designentscheidung der menge der exception, nicht so sehr vom code an sich;)

    die alternative mit der ich jetzt arbeite hat nicht eine exception die geworfen werden wuerde. fuer alles was schiefgeht gibt es fallbacks und die streamen in den log.

    der user will eine datei speichern, du kannst sie aber nicht speichern weil platte voll ist.
    was dann?

    gut: du gibst eine warnung aus beim ersten mal und danach nur noch ins log, und laeufst weiter als waere nichts (programtechnisch: in den error-stream eine warnung "Wurde nicht gespeichert" ausgeben und return FAIL;)
    schlecht 1: du wirfst ne exception die irgendwo gefangen wird und dem user sagt "kritischer fehler: 'datei konnte nicht gespeichert werden' program wird beendet"
    schlecht 2: du gibst bei jedem versuch zu speichern (z.b. eine sequenz von bildern) immer wieder "geht nicht" aus.

    ich finde exceptions sollte man wirklich nur schmeissen wenn man sich garnicht mehr anders zu helfen weiss, also nicht bei "errors", sondern wirklich bei blockierenden ereignissen. Passiert bei unserer lib nur vom system aus, z.b. access violation.

    definiere bitte was du fuer unterschiedliche fehlertypen kennst.

    hab ich schon, errors die zwar passieren, aber kein grund sind den programmfluss zu unterbrechen. exceptional errors, fehler von denen man nicht erwarten wuerde dass sie passieren und sie deswegen "ausnahme fehler" sind.

    wenn also eine funktion etwas macht und man weiss dass diese aktion fehlschlagen kann, dann ist es keine ausnahme/exception. um dein beispiel von "platte ist voll" aufzugreifen, fopen wirft keine exception wenn eine datei nicht geoeffnet werden konnte. du hast einen return-wert, der dir einen der moeglichen resultate der aktion zurueckliefert. genau so sollte das programm dann auch weiter verlaufen. dein serializer wird initialisiert, er gibt dir ein fehler zurueck und du gibst ne warnung an den user aus oder in ein log, dass nicht gespeichert wird.
    (ja, ich weiss, fstreams koennen auch exceptions werfen, deswegen war mein beispiel mit fopen 😉 )

    Ich kenne nur 2 Arten: fatale fehler (logik fehler) die nie auftreten duerfen (interne invarianten verletzt) -> assert. Dann kenne ich noch "normale" Fehler, wie eben zB festplatte voll (laufzeit fehler - koennen immer auftreten) und das wars. Was kennst du noch fuer Fehler? Am besten mit Beispiel.

    fehler die man erwartet hat und behandeln kann

    foo(void* bar)
    {
     assert(bar);
     if(!bar)
     {
       ...
       return...;
     }
    .
    .
    .
    }
    //or
    save(const char* foo)
    {
      if(!open(foo))
      {
        ....
        return .... ;
      }
    write
    write
    close
    

    ausnahmefehler die man nicht erwartet hat

    foo(float bar)
    {
     return bar*bar;  //float exception: overflow, oder NAN...
    }
    
    bar::foo()
    {
     return member;   //this is 0 or invalid
    }
    

    zu ausnahmefehlern wuerde ich auch zaehlen wenn man von einer verwendeten funktion/bibliothek keine chance hat den fehler zu behandeln

    HalfSize()
    {
    myVector.resize(myVector.size()/2);  //out of mem, could not allocate destination buffer
    }
    

    entsprechend schreib ich kein try-catch block unmittelbar um diese stellen, denn ich weiss dass es in 99.99% der laufzeit bloedsinn waere, aber ich weiss auch, dass es in ausnahmefaellen passiert.



  • rapso schrieb:

    die if abfrage kostet dich weit weniger als ein catch block.

    Nur wenn eine exception fliegt. Wenn keine fliegt kostet das if deutlich mehr (und du brauchst deutlich mehr ifs als catches)

    bilddatei nicht gefunden -> dummy bild
    config nicht gefunden -> default settings
    out of memory -> alte resourcen freigeben und nochmal versuchen
    sound dll nicht geladen -> dummy interface zurueckgeben
    etc.

    Wenn es ein fallback gibt, ist es kein Fehler.
    weil dann mache ich ein if(exists) und öffne nur wenn die datei da ist.

    wenn also eine funktion etwas macht und man weiss dass diese aktion fehlschlagen kann, dann ist es keine ausnahme/exception. um dein beispiel von "platte ist voll" aufzugreifen, fopen wirft keine exception wenn eine datei nicht geoeffnet werden konnte. du hast einen return-wert, der dir einen der moeglichen resultate der aktion zurueckliefert. genau so sollte das programm dann auch weiter verlaufen. dein serializer wird initialisiert, er gibt dir ein fehler zurueck und du gibst ne warnung an den user aus oder in ein log, dass nicht gespeichert wird.

    Das sehe ich komplett anders.
    Der User hat hier darauf hingewiesen zu werden dass seine Daten nicht gespeichert werden - man kann ja nicht einfach die daten des users wegwerfen...

    vl muss er ja auch nur ein anderes volume auswählen...



  • bilddatei nicht gefunden -> dummy bild
    config nicht gefunden -> default settings
    sound dll nicht geladen -> dummy interface zurueckgeben

    das sind fallbacks die du in deiner APPLIKATION einbauen kannst, wenn du magst, die aber ganz sicher nichts in einer library verloren haben die z.b. blider lädt! die library hat gefälligst in diesen fällen eine exception zu werfen, die du fängst, und dann dein dummy bild zurückgibst.

    out of memory -> alte resourcen freigeben und nochmal versuchen

    ist nur in den seltensten fällen möglich, aber ja. dafür gibt's ja extra hooks in denen du das erledigen kannst.


Anmelden zum Antworten