Wie funktioniert diese Implementierung von Ausnahmen Arbeit verketten?
-
01-10-2019 - |
Frage
Ich fragte vorher eine Frage darüber, wie Verkettungs Ausnahmen in C ++, und eine der Antworten vorgesehen, um eine raffinierte Lösung, wie es getan werden kann. Das Problem ist, dass ich den Code nicht verstehen, und diese Art der Diskussion in den Kommentaren zu haben versucht, ist einfach zu viel zuviel Mühe. Also ich dachte, es ist besser, völlig eine neue Frage zu beginnen.
Der Code wird auch weiter unten, und ich habe jeden Abschnitt eindeutig gekennzeichnet, die ich nicht bekommen. Eine Beschreibung von dem, was ich nicht verstehe, ist unter dem Code enthält. Der Code wurde geschrieben von Potatoswatter .
Code
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;
// ----------------------------------------------------------------
// How does this work (section 1)?
throw;
// ----------------------------------------------------------------
} catch ( chained_exception &prev ) {
// ----------------------------------------------------------------
// How does this work (section 2)?
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() {
// --------------------------------------------------------------------
// How does this work (section 3)?
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 ) {
// Print ep->what() to std::cerr
}
}
}
try {
throw chained_exception( "meh!" );
} catch ( chained_exception &e ) {
for ( chained_exception *ep = &e; ep->link; ep = ep->link ) {
// Print ep->what() to std::cerr
}
}
}
int main() try {
// ------------------------------------------------------------------------
// How does this work (section 4)?
throw chained_exception(); // create dummy end-of-chain
// ------------------------------------------------------------------------
} catch( chained_exception & ) {
// body of main goes here
f();
}
Ausführen des Codes gibt die folgende Ausgabe:
bah
humbug!
meh!
Was ich nicht verstehe
-
throw;
innerhalbtry
-Block: Ich habe das noch nie gesehen. Der einzige Ort, wo ich gedacht habethrow;
gültig zu sein war in einemcatch
-Block erneut auslösen, was gefangen wurde. Was bedeutet das? Einige Debuggen offenbar zeigt, dass die ausgelöste Ausnahme ist das, was vorher geworfen wurde, aber das war in einem ganz anderentry
-Block. In der Tat, es war auch außerhalb derstruct
Erklärung! -
Swap Felder: Warum brauchen wir auf Swap die Ausnahmefelder? Wäre das nicht nur das Kopieren des Zeigers genug sein? Ist das die Strukturen zu verhindern, der die Felder am Punkt von aus dem Heap vorzeitig gelöscht werden?
-
Überprüfen
link
undlink
den Link: Ich verstehe, kann prüfen, oblink
nichtNULL
ist (obwohl einNULL
Zeiger zu löschen hat keine Auswirkungen), aber warum die Notwendigkeit, dielink
die Verbindung zu überprüfen? -
Werfen Dummy Ausnahme: Warum wird diese Dummy benötigt? Es wird geworfen, aber dann fallen gelassen. Warum brauchen wir das als ein Ende der Kette?
Lösung
Clever-Code - ein dickes Lob an potatoswatter auf diesem. Ich denke, dass ich müsste allerdings eine gewisse Art und Weise um das letzte Element finden.
-
throw;
rethrows die aktive Ausnahme. Es ist nur gültig, wenn eincatch
Block auf dem Stapel befindet. Ich kann mich nicht erinnern, wo ich auf diesem tidbit kam, aber es war wahrscheinlich auf SO im Zusammenhang mit einer anderen Frage. Der bloße Wurf gibt uns auf die aktuelle Ausnahme zugreifen, indem sie in derchained_exception
Konstruktor zu kontrollieren. Mit anderen Worten,prev
im Konstruktor ist ein Verweis auf die Ausnahme, dass wir gerade bearbeiten. -
Sie sind hier richtig. Dies verhindert, dass doppelte Streichung.
-
Die Sentinel-Ausnahme, die man in
main
geworfen, sollte nie gelöscht werden. Das ein Identitätsmerkmal dieser Ausnahme ist, dass eslink
Mitglied istNULL
. -
Dies ist der Teil, dass ich nicht wie, aber kann nicht denken eine einfache Möglichkeit, um. Der einzige sichtbare
chained_exception
Konstruktor kann nur aufgerufen werden, wenn eincatch
Block aktiv ist. IIRC, ein nackter Wurf ohne aktivencatch
Block ist ein No-No. Also, die Abhilfe ist inmain
zu werfen und die gesamten Code in demcatch
Block setzen.
Nun, wenn Sie diese Methode in Multi-Threaded-Code versuchen, stellen Sie sicher, dass Sie verstehen, (4) sehr gut. Sie wird diesen Punkt in der Thread-Eintrag replizieren.