Frage

    

Diese Frage bereits eine Antwort hier:

         

Ich habe gerade die Arbeit an einem C ++ - Programm, in dem ich meine eigene Ausnahmen implementiert haben (obwohl von std :: exception abgeleitet). Die Praxis, die ich angelegt habe, wenn eine Ausnahme eine Kettenreaktion verursacht, den Fehler propagiert nach oben und was zu anderen Ausnahmen, ist die Fehlermeldung an jedem entsprechenden Schritt für die Module (lesen Klassen) verketten. D. h die alte Ausnahme selbst fallen gelassen wird und eine neue Ausnahme geschaffen, aber mit einer längeren Fehlermeldung.

Dies mag für mein kleines Programm gearbeitet, aber ich war nicht sehr zufrieden mit meinem Ansatz am Ende. Zur einem Zeilennummer (wenn auch nicht in dem Moment angelegt wird) und die Dateinamen werden mit Ausnahme der letzten Ausnahme nicht zurückgehalten wird; und wirklich, dass die Informationen von besonderem Interesse in der ersten Ausnahme.

Ich stelle dar, das besser behandelt worden sein könnte durch Ausnahmen zusammen verketten; das heißt, die alte Ausnahme im Konstruktor der neuen Ausnahme vorgesehen. Aber, wie das umgesetzt werden würde? Keine Ausnahmen sterben, wenn sie gehen aus dem Anwendungsbereich von dem Verfahren, wodurch eine Verhinderung zu verwenden Ausnahme Zeigern? Und wie die Ausnahme kopieren und zu speichern, wenn die Ausnahme von jeder abgeleiteten Klasse sein?

Dies führt mich schließlich zu prüfen, ob Ausnahmen in C ++ Verkettungs ist so eine gute Idee. Vielleicht sollte man nur eine Ausnahme erstellen und fügen Sie dann zusätzliche Daten zu, dass (wie ich zu tun habe, aber wahrscheinlich in einer viel besseren Weise)?

Was ist Ihre Antwort darauf? Should Ausnahmen von einem anderen verursacht verkettet werden zusammen eine Art „Ausnahme Spur“ zu behalten - und wie diese umgesetzt werden sollte? - oder sollte es eine einzige Ausnahme verwendet werden und zusätzliche Daten angehängt - und wie soll das geschehen

War es hilfreich?

Lösung

Es ist notwendig, die Daten aus einem Ausnahmeobjekt, in eine Kette zu kopieren, wenn Sie es wollen den catch Block überleben, die es empfängt, abgesehen von rethrow von throw;. (Einschließlich zum Beispiel, wenn der catch Block beendet durch einen throw obj;.)

Dies kann, indem Daten erfolgt auf dem Heap gespeichert werden und die Implementierung swap (move in C ++ 0x) auf Ihren privaten Daten innerhalb der Ausnahme, zum Beispiel.

Natürlich müssen Sie vorsichtig sein, wenn die Halde mit Ausnahmen verwenden ... aber dann wieder, in den meisten modernen Betriebssystemen, Speichermehrfachvergabe verhindert vollständig new jemals zu werfen, zum Guten oder zum Schlechten. Ein gutes Gedächtnis-Marge und Ausnahmen von der Kette nach dem vollständigen Zusammenbruch fallen sollte es sicher halten.

struct exception_data { // abstract base class; may contain anything
    virtual ~exception_data() {}
};

struct chained_exception : std::exception {
    chained_exception( std::string const &s, exception_data *d = NULL )
        : data(d), descr(s) {
        try {
            link = new chained_exception;
            throw;
        } catch ( chained_exception &prev ) {
            swap( *link, prev );
        } // catch std::bad_alloc somehow...
    }

    friend void swap( chained_exception &lhs, chained_exception &rhs ) {
        std::swap( lhs.link, rhs.link );
        std::swap( lhs.data, rhs.data );
        swap( lhs.descr, rhs.descr );
    }

    virtual char const *what() const throw() { return descr.c_str(); }

    virtual ~chained_exception() throw() {
        if ( link && link->link ) delete link; // do not delete terminator
        delete data;
    }

    chained_exception *link; // always on heap
    exception_data *data; // always on heap
    std::string descr; // keeps data on heap

private:
    chained_exception() : link(), data() {}
    friend int main();
};

void f() {
    try {
        throw chained_exception( "humbug!" );
    } catch ( std::exception & ) {
        try {
            throw chained_exception( "bah" );
        } catch ( chained_exception &e ) {
            chained_exception *ep = &e;
            for ( chained_exception *ep = &e; ep->link; ep = ep->link ) {
                std::cerr << ep->what() << std::endl;
            }
        }
    }

    try {
        throw chained_exception( "meh!" );
    } catch ( chained_exception &e ) {
        for ( chained_exception *ep = &e; ep->link; ep = ep->link ) {
            std::cerr << ep->what() << std::endl;
        }
    }
}

int main() try {
    throw chained_exception(); // create dummy end-of-chain
} catch( chained_exception & ) {
    // body of main goes here
    f();
}

Ausgang (entsprechend mürrisch):

bah
humbug!
meh!

Andere Tipps

Da diese Frage wurde gebeten, bemerkenswerte Änderungen mit C ++ 11 zum Standard gemacht worden. Ich bin immer dies in Diskussionen über Ausnahmen fehlt, aber der folgende Ansatz, nisten Ausnahmen, funktioniert der Trick:

Verwenden Sie std::nested_exception und std::throw_with_nested

Es wird auf Stackoverflow beschrieben hier und hier , wie können Sie einen Backtrace auf Ausnahmen für einen Debugger, ohne dass in Ihrem Code oder umständliche Protokollierung, indem Sie einfach einen richtigen Exception-Handler schreiben, die verschachtelten Ausnahmen erneut auslösen wird .

Da Sie dies mit jeder abgeleitete Exception-Klasse tun können, können Sie eine Vielzahl von Informationen zu einem solchen Backtrace hinzuzufügen! Sie können auch einen Blick auf meine MWE auf GitHub , wo ein Backtrace etwas aussehen würde wie folgt aus:

Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"

Sie können auf diese aussehen soll: http://www.boost.org/doc/libs/1_43_0/libs/exception/doc/boost-exception.html

Es ist etwas anderer Ansatz zu dem, was MS tat in C #, aber es scheint, Ihre Anforderungen zu entsprechen.

Eine weitere Idee ist es, die relevanten Daten zu Ihrem Ausnahmeobjekt hinzuzufügen, dann mit einer nackten throw; Anweisung verwenden, um es erneut zu werfen. Ich denke, die Stack-Informationen werden in diesem Fall beibehalten, und so können Sie immer noch die ursprüngliche Quelle der Ausnahme wissen würden, aber Tests wären eine gute Idee sein.

ich wette, da, ob von einer Stack-Informationen überhaupt verfügbar ist, wird die Umsetzung definiert, dass Implementierungen noch breiter in ob es erhalten oder nicht nach einer bloßen throw; Aussage in irgendeiner Weise variieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top