Leidiges Thema: Error Handling und Error Reporting



  • Aber du bist damit schon sehr auf C Niveau. Exceptions sind ein elementarer Bestandteil von C++.

    Ich frage mich daher, welche Art von Antwort du hier wohl erwartest.
    Sofern man keine Exceptions verwenden kann, musst du alle Rückgabewerte prüfen.

    try
    {
     MyClass c("bla");
    }
    // ...
    

    Sowas ist entsprechend nicht mehr möglich (Exception im Konstruktor).

    Du musst also folgendes machen:

    MyClass c;
    
    if (c.init("bla"))
    {
    }
    

    Deine Frage klingt aber fast so, als würdest du auf einen Ansatz hoffen Exceptions nachzubauen. Aber was soll das bringen?

    Vielleicht kann man eine Art Fehler-Stack bauen und jede Funktion fragt einfach vorher ab, ob es einen Fehler gab:
    if (!ErrorStack.Empty()) return;

    Auf diese Weise würdest du dann irgendwann wieder in der main landen und könntest dort den Fehler ausgeben. Aber du musst verstehen, dass das echt dämmlich ist, weil du damit deine Codegröße auch nicht gerade schonst und Exceptions das vermutlich viel effizienter lösen.

    Letztendlich müsstest du es einfach ausprobieren. Du könntest dann auch eine neue Alloc-Funktion basteln, die im Fehlerfahll auch den Fehler-Stack anspricht.

    Aber na ja...



  • Danke für deine Antwort,

    ich weiß, dass ich damit viele Vorteile verliere, aber was soll ich machen, Vorgabe ist Vorgabe :(.

    Dass mit den Rückgabewerten ist mir klar, ich wollte nur hören ob es irgendwo irgendwie andere Ideen bezüglich möglicher Fehlerbehandlung gibt.

    Danke.



  • schau dir doch mal die fehler behandlung von großen systemen an funktioniert doch immer "fast" gleich 😉

    ________________
    Wenn man keine Ahnung hat, einfach mal die Fresse halten - Dieter Nuhr



  • Übrigen kannst du ja auch gar keine STL verwenden, oder?

    Schließlich nutzt die STL auch Exceptions und new.

    An dieser Stelle fängt es an richtig hässlich zu werden 😃 Kannst du mit virtuellen Funktionen arbeiten?

    Eventuell kannst du dir ein Inteface für Fehler basteln das jede Klasse implementiert.



  • Das was ich z.B. verwende, ist folgendes:

    Der return jeder Funktion liefert einen Fehlercode.

    Das sieht dann z.B. so aus:

    int err = fnXXX(...);
    if (!err)
        err = fnYYY(...);
    else
    {
        // Fehlerbehandlung, wenn sinnvoll möglich, Plan B, ...
    }
    
    if (err)
    {
        // Fehlerlogging
        printf("Fehler");
    }
    

    Die Fehlernummern(kreise) werden dann typischerweise festgelegt und
    sollten in einer wie auch immer gearteten Liste verwaltet werden.
    Aus der Nummer kann man, bei Eindeutigkeit, auch automatisch einen Text machen.

    Ich finde daß deutlich besser als exeptions,
    weil ich sowieso immer Fehler loggen muss.
    Und nicht nur da wo sie auftreten, sondern im kompletten Callstack.
    Hierbei sollte jede Call Ebene ihre Kontextinformationen mit loggen.
    So kann man dann auch tatsächlich verstehen wie ein Fehler zustande gekommen ist.

    Gruß Frank



  • Frank Erdorf schrieb:

    Ich finde daß deutlich besser als exeptions,
    weil ich sowieso immer Fehler loggen muss.
    Und nicht nur da wo sie auftreten, sondern im kompletten Callstack.
    Hierbei sollte jede Call Ebene ihre Kontextinformationen mit loggen.
    So kann man dann auch tatsächlich verstehen wie ein Fehler zustande gekommen ist.

    lol



  • am anfang war der code dann kam die fehlerbehandlung und schließlich die bugs LOL



  • Ohne Exceptions und Debug bleibt nur die altbewährte Methode mit Kontrollausgaben auf dem Bildschirm oder in einer Datei. Beides kann sehr effizient sein. Unkritisches wird auskommentiert und kann jederzeit reaktiviert werden. Ein sauberes Design ist vorrausgesetzt.



  • berniebutt schrieb:

    Ohne Exceptions und Debug bleibt nur die altbewährte Methode mit Kontrollausgaben auf dem Bildschirm oder in einer Datei.

    Logging ist nur ein sehr kleiner Teil der Fehlerbehandlung.



  • volkard schrieb:

    Frank Erdorf schrieb:

    Ich finde daß deutlich besser als exeptions,
    weil ich sowieso immer Fehler loggen muss.
    Und nicht nur da wo sie auftreten, sondern im kompletten Callstack.
    Hierbei sollte jede Call Ebene ihre Kontextinformationen mit loggen.
    So kann man dann auch tatsächlich verstehen wie ein Fehler zustande gekommen ist.

    lol

    Liegt halt daran, dass der Informationsgehalt von C++ Exception gleich Null ist.

    Wenn es ein singlethread System ist, kannst du auch ohne großen Aufwand ein globales Fehlerflag oder einen Fehlerstack oder getLastError oder sowas verwenden.



  • Liegt halt daran, dass der Informationsgehalt von C++ Exception gleich Null ist.

    Vor allem, wenn man immer
    std::exception("Es ist irgend ein Fehler passiert")
    wirft. Aber dazu gibt es, soweit ich weiß, keine polizeiliche Verpflichtung.



  • volkard schrieb:

    Logging ist nur ein sehr kleiner Teil der Fehlerbehandlung.

    Fehler sind aber dazu da, möglichst vermieden zu werden. Wenn ich etwas mit Logging erledigen kann, schmeisse ich nichts anderes an oder nehme es nur im absoluten Notfall. Da sind wir aber bei dem Thema 'Möglichst fehlerfreies und wartungsfreunliches Programm-Design'. Kein System oder Compiler kann Denkfehler oder schlechtes Design kompensieren! :p



  • volkard schrieb:

    Liegt halt daran, dass der Informationsgehalt von C++ Exception gleich Null ist.

    Vor allem, wenn man immer
    std::exception("Es ist irgend ein Fehler passiert")
    wirft. Aber dazu gibt es, soweit ich weiß, keine polizeiliche Verpflichtung.

    Wenn du mir jetzt noch zeigst wie man neben einem sinnvollen Text auch noch einfach und systemunabhängig einen Stacktrace aus ner std::exception bekommt, dann bin ich voll begeistert.

    ~Zuletzt bearbeitet von schoolsout4ever am 13:45:35 25.07.2010, insgesamt 72-mal bearbeitet~



  • schoolsout4ever schrieb:

    Wenn du mir jetzt noch zeigst wie man neben einem sinnvollen Text auch noch einfach und systemunabhängig einen Stacktrace aus ner std::exception bekommt, dann bin ich voll begeistert.

    Das zeige ich Dir, wenn Du mir zeigst, wie man mit einer Säge Schrauben festbohrt.



  • Damit geht das ganz einfach. Alternativ auch damit.



  • schoolsout4ever schrieb:

    Damit geht das ganz einfach. Alternativ auch damit.

    was bedeutet festbohrt?



  • festbohrt? schrieb:

    was bedeutet festbohrt?

    Das ist ein genialer Neologismus. Er wurde heuer von Pattex in einem Werbespot verbreitet. Da mußt eine Dame etwas nicht "festbohren". Gemeint war natürlich Dübeln.
    Ich mag das Wort. Es ist noch toller als "Ich stelle ein Schitzel in die Mikrowelle." Das ist ja nur richtig falsch. Aber festbohren ist so toll widersprüchlich.

    Vor wenigen Wochen gab es nur zwei google-Treffer zu "festbohren". Und schau, was heute schon los ist! 😮 😮 😮
    http://www.google.de/#hl=de&&sa=X&ei=5VRMTKLOL8SZOIuy9JUD&ved=0CCMQBSgA&q=festbohren&spell=1&fp=edb299ab19385cd9



  • festbohrt? schrieb:

    schoolsout4ever schrieb:

    Damit geht das ganz einfach. Alternativ auch damit.

    was bedeutet festbohrt?

    Man nimmt eine Handkreissäge, macht seitlich eine Schraube hin und hält das an die Wand und gibt Gas. 🙄



  • eher bohrt man solang in ein stahlträger bis der bohrer festschmiltzt das nennt sich dann auch festgebohrt



  • schoolsout4ever schrieb:

    Man nimmt eine Handkreissäge, macht seitlich eine Schraube hin und hält das an die Wand und gibt Gas. 🙄

    Das muß ich wohl gelten lassen.

    Eigentlich wollte ich den Aufrufkontext klassisch festhalten in einem entsprechenden globalen Stack. Aber dann ist es mir gekommen, daß ich dafür nicht bezahlen muß, wenn ich wie folgt trickse:
    Beim GCC für Exceptions angeblich keine Laufzeitkosten mehr sind, wenn sie nicht fliegen - außer mittelbar durch größere exe-Datei und so.

    #include <iostream>
    #include <cmath>
    #include <stdexcept>
    #include <sstream>
    #include <string>
    using namespace std;
    
    class funny_exception:public std::runtime_error{
    	public:
    	string context;
    	funny_exception(const char* msg):
    		std::runtime_error(msg){
    		}
    	~funny_exception() throw(){
    	}
    };
    
    double wurzel(double x)
    try{
    	if(x>100)
    		throw funny_exception("Irgend ein Fehler ist aufgetreten");
    	return sqrt(x);
    }
    catch(funny_exception& ex){
    	ostringstream out;
    	out<<"In "<<__FILE__<<':'<<__LINE__<<" wurzel("<<x<<')'<<'\n';
    	ex.context+=out.str();
    	throw;
    }
    
    double berechneHypotenuse(double a,double b)
    try{
    	return wurzel(a*a+b*b);
    }
    catch(funny_exception& ex){
    	ostringstream out;
    	out<<"In "<<__FILE__<<':'<<__LINE__<<" berechneHypotenuse("<<a<<','<<b<<')'<<'\n';
    	ex.context+=out.str();
    	throw;
    }
    
    int main(){
    	try{
        cout << berechneHypotenuse(3,101) << endl;
    	}
    	catch(funny_exception& ex){
    		cout<<ex.context;
    		cout<<ex.what()<<'\n';
        return 1;
    	}
    }
    

    Ausgabe:

    In D:\src\research\exctest\main.cpp:26 wurzel(10210)
    In D:\src\research\exctest\main.cpp:37 berechneHypotenuse(3,101)
    Irgend ein Fehler ist aufgetreten
    

Anmelden zum Antworten