Checked Exceptions



  • Hallo zusammen,

    gibt es in C++ auch eine Möglichkeit vom Compiler checken zu lassen,
    ob alle Exceptions gecatcht werden? Oder nur bei bestimmten Compilern?
    Ich verwende gcc unter KDevelop

    Kann ich irgendwie den Methoden-Stack ausgeben lassen wie in Java?

    Gruß,
    CSpille



  • Afaik nein.



  • CSpille schrieb:

    gibt es in C++ auch eine Möglichkeit vom Compiler checken zu lassen,
    ob alle Exceptions gecatcht werden?

    Imo dürfte sowas nicht möglich sein. Wenn du aber sichergehen willst, dass alle Exceptions gefangen werden, dann bau ein catch (...) in main ein.

    CSpille schrieb:

    Kann ich irgendwie den Methoden-Stack ausgeben lassen wie in Java?

    Bin mir zwar nicht ganz sicher, was du mit Methoden-Stack meinst. Falls du damit den Call-Stack meinst, ja das geht. Allerdings nur mit einigen nachträglichen Eingriffen. Für bestehenden Code geht das nicht, zumindest nicht portabel.



  • Kannst du mal erklaeren wie du an den Call-Stack kommst? Weisst du irgendwie an welcher Adresse der liegt, bzw. vor oder nach welchem Segment, sodass du dir die Adresse errechnen kannst?
    Würd mich mal interessieren.



  • Theoretisch würde die Exception-Abfang-Erzwingung funktionieren. Aber praktisch lässt sich das in C++ schwer umsetzen. Alleine deshalb schon, weil in der Funktions/Methoden-Sig nicht stehen muß, was geworfen wird. Das kannst du also vergessen, du bist hier in der C++ Welt. 😉

    Den Callstack kann man so auch nicht ausgeben, außer man ist in der Debug-Compilierung und man baut COmpiler-Spezifische printouts ein. Aber ist auch nicht das was du eigentlich willst.

    Bedenke eines: C++ ist eine Compiler-Sprache! D.h. zur Laufzeit bekommst du keine Informationen, RTTI ist seeeeeeeeeeeeeehr mager und kann ja sogar abgeschaltet werden (was dich ja doch stutzig machen sollte).

    Denk C++! 😃



  • Das hier sollte dir für Windows weiterhelfen.
    http://www.codeproject.com/threads/StackWalker.asp
    Ne plattformunabhängige Lösung kenn ich nicht.



  • Hilft std::uncaught_exception nur bei von std::exception abgeleiteten Objekten?



  • Ich beschränke mich immer darauf, einer Exception __FILE__ und __LINE_ mitzugeben, dann weiß ich in main wenigstens noch, wo sie her kommt.



  • Ger001 schrieb:

    Kannst du mal erklaeren wie du an den Call-Stack kommst? Weisst du irgendwie an welcher Adresse der liegt, bzw. vor oder nach welchem Segment, sodass du dir die Adresse errechnen kannst?

    Der Call-Stack "liegt" nirgendwo, zumindest aus C++ Sicht. Entweder bauen Compiler sich diesen selbst (zwecks Debugging) oder du machst das manuell. Ersteres ist allerdings nicht portabel. Es gibt zwar noch die Möglichkeit, den Stack Speicher durchzugehen, aber dies ist vielmehr ein indirekter Call-Stack, da dort lediglich Rücksprungadressen stehen.
    Die einzige Möglichkeit einen relativ portablen Call-Stack zu implementieren, ist, diesen selbst zu integrieren. Dazu bastelst du dir eine Klasse, welche pro Funktion einmal instanziert wird. Welche Informationen du dort rein packst ist dir überlassen. Sinnvoll wäre zumindest der Name der Funktion. Die meisten C++ Compiler kennen C99, dh du kannst dann __func__ benutzen. Und selbst Compiler, die das nicht kennen, bieten dafür idR ein eigenes Makro bzw eine eigene Konstante an. Die erstellte Instanz wird dann in einen globalen Stack-Container gepusht und mit dem dtor wieder gepopt. Der einzige Nachteil an dieser ganzen Geschichte ist, dass du prkatisch in jeder Funktion am Beginn die Instanzierung vornehmen musst. Zwar kann man das mit 'nem Makro noch etwas anwenderfreundlicher verpacken, hinschreiben muss man es aber trotzdem.



  • Michael E. schrieb:

    Hilft std::uncaught_exception nur bei von std::exception abgeleiteten Objekten?

    Ich bekomms net hin dass std::uncaught_exception true gibt... Das hab ich versucht:

    #include <iostream>
    #include <exception>
    
    using namespace std;
    
    struct Error
    {
        Error() {
            cout << "Error::Error()" << endl;
            if(uncaught_exception()) {
                cout << "Uncaught Exception in Error::Error()." << endl;
            }
        }
    
        ~Error() {
            cout << "Error::~Error()" << endl;
        }
    };
    
    struct Foo
    {
    
        Foo() {
            cout << "Foo::Foo()" << endl;
        }
    
        ~Foo() {
            cout << "Foo::~Foo()" << endl;
            if(uncaught_exception()) {
                cout << "Uncaught Exception in Foo::~Foo()." << endl;
            }
        }
    
        template<class T>
        void Bar(T err) {
            cout << "Foo::Bar()" << endl;
            throw err;
        }
    
    };
    
    int main()
    {
        try {
            Foo foo;
            foo.Bar(Error()); // foo.Bar(runtime_error("x"));,
        } catch(...) {
            cout << "Exception handling in int main()" << endl;
        }
        cout << "End";
        cin.get();
    }
    

    Ausgabe (bei std-exception das selbe nur ohne Error::x meldungen)

    Foo::Foo()
    Error::Error()
    Foo::Bar()
    Error::~Error()
    Error::~Error()
    Foo::~Foo()
    Exception handling in int main()
    Error::~Error()
    End
    

    Irgendwie hab ich das net erwartet... Ich dachte mehr an:

    Foo::Foo()
    Foo::Bar()
    Error::Error()
    Uncaught Exception in Error::Error().
    Foo::~Foo()
    Exception handling in int main()
    Error::~Error()
    End
    

    habs unter BCD6 getestet weil ich nix anderes da hab.
    may be im just stupid... 😞

    /edit: der gcc sagt wieder was anderes TT



  • groovemaster schrieb:

    Der einzige Nachteil an dieser ganzen Geschichte ist, dass du prkatisch in jeder Funktion am Beginn die Instanzierung vornehmen musst.

    Ich sage dazu nur: Aspekt Orientierte Programmierung hilft da weiter!

    http://www.aspectc.org/



  • FireFlow schrieb:

    foo.Bar(Error()); // foo.Bar(runtime_error("x"));,
    

    Das lokale Objekt vom Typ Error wird schon vor Ausführung des Rumpfes von Foo::Bar<>() konstruiert. Deshalb wurde noch gar keine Exception geworfen.



  • Michael E. schrieb:

    FireFlow schrieb:

    foo.Bar(Error()); // foo.Bar(runtime_error("x"));,
    

    Das lokale Objekt vom Typ Error wird schon vor Ausführung des Rumpfes von Foo::Bar<>() konstruiert. Deshalb wurde noch gar keine Exception geworfen.

    Ok das hab ich nun kapiert... Ich hab auch verstanden dass weil ich kein Copy C'tor hab ich mehr Dekonstruktoraufrufe hab als Konstruktoraufrufe (hoffe ich zumindest dass es daran liegt, muss nochmal testen). Nun ich habs nochmal im GCC und in VC8 getestet und da bekomm ich jeweils die Meldung `Uncaught Exception in Foo::~Foo().` - Im Borland aber nicht, ist der BCB in der Hinsicht mal wieder nicht Standardkonform oder ist das Verhalten undefined?



  • Will man unter Linux einen Backtrace haben nimmt man die Funktionen aus

    #include <execinfo.h>

    http://www.gnu.org/software/libc/manual/html_node/Backtraces.html

    In unserem Projekt wird das so gemacht, dass wir nur eigene Exceptions werfen. Diese sammeln im Konstruktor die Funktionszeiger auf, die backtrace() liefert.

    Wird die Exception dann gefangen, kann man sich den Backtrace mit Namen von backtrace_symbols() ausgeben lassen.



  • Funzt das auch im Release-Modus ohne Debug-Infos?



  • Fireflow:

    ISO/IEC 14882:1998 schrieb:

    18.6.4 uncaught_exception

    bool uncaught_exception();

    Returns: "true" after completing evaluation of a throw-expressionuntil either completing initialization of the exception-declaration in the matching handler or entering "unexpected()" due to the throw; or after entering "terminate()" for any reason other than explicit call to "terminate()". [Note: This includes stack unwinding (15.2). --end note]



  • Kann das also nur in Dekonstruktoren true ergeben? Ich meine danach wird der Block ja sofort verlassen und in den catch-Block gesprungen.



  • backtracing schrieb:

    Funzt das auch im Release-Modus ohne Debug-Infos?

    Ja, kann dir aber nur das sagen, was auch vorhanden ist. Das ist dann oft recht wenig.



  • FireFlow schrieb:

    Kann das also nur in Dekonstruktoren true ergeben?

    In deinem Fall ja.



  • Michael E. schrieb:

    FireFlow schrieb:

    Kann das also nur in Dekonstruktoren true ergeben?

    In deinem Fall ja.

    Hast du villeicht mal nen Beispiel wo es nicht im Dekonstruktor ist und trotzdem true ergibt? Mir fällt nix ein...



  • Sollte man eh nie benutzen.
    Hier hast Du interessante Lektüre dazu:
    http://www.gotw.ca/gotw/047.htm

    Zitat von Sutter:
    Is there any other good use for uncaught_exception? Discuss and draw conclusions.

    Unfortunately, I do not know of any good and safe use for std::uncaught_exception. My advice: Don't use it.


Anmelden zum Antworten