Exception Auftreten im Destruktor
-
Hallo zusammen,
ich habe hier ein ziemlich doofes Problem. Im Prinzip lässt es sich auf folgendes Konstrukt runterbrechen:
class ScopedTransaction { DatabaseDAC* db_; public: ScopedTransaction ( DatabaseDAC* db ) : db_( db ) { assert( db_ ); begin(); } ~ScopedTransaction () { rollback(); } void begin() { if( db_->connected() ) db_->StartTransaction(); } void commit() { if( db_->connected() ) db_->Commit(); } void rollback() { if( db_->connected() ) db_->Rollback(); } }; void func( DatabaseDAC* db ) { try { ScopedTransaction ST( db ); // SQL Zeugs hier g.commit(); } catch( runtime_error& rte ) { } }Wenn in der Funktion
funcinnerhalb des try-catch-Blocks eine Exception auftritt wird vor dem Sprung in den Exception Handler der Destruktor vonScopedTransactionaufgerufen. Der wirft selbst wiederum eine Exception und läuft dadurch in unendliche Rekursion und schließlich in einen Stack Überlauf.
Das Problem tritt auf, wenn innerhalb der Transaktion die Verbindung zur db verloren geht. Eins der SQL Statements schlägt fehl und wirft eine Exception. Dann werden alle Variablen im try-catch Block zerstört, was zur Folge hat, dass im Destruktor vonScopedTransactionein Rollback ausgeführt werden soll. Dummerweise liefertdb_->connected()nochtruezurück, sodass erneut eine Exception geworfen wird und zu dem Stack Overflow führt.
Wie kriegt man sowas in den Griff?
-
Wenn während der Exceptionbehandlung eine Exception geworfen wird, sollte std::terminate aufgerufen werden (was in diesem Fall vermutlich richtig wäre). Eigentlich kann es da keine Rekursion geben.
-
Gut möglich, dass sich unser Compiler da nicht an den Standard hält, der ist ja schließlich von Borland/Embarcadero.

Wennstd::terminateaufgerufen wird ist da vermutlich wirklich nicht mehr viel zu machen :(. Durch Setzen eines terminate-Handlers kann ich höchstens noch beweisen, dass der Abbruch durch diesen Mechanismus erfolgt ist.
-
Du kannst es natürlich mit http://en.cppreference.com/w/cpp/error/uncaught_exception probieren, falls der Compiler das beherrscht. Ist nur die Frage, ob man in so einem Fall noch sinnvoll weitermachen kann.
-
Hallo DocShoe,
Herb Sutter schlägt vor, die Exception innerhalb des Destruktor abzufangen.
~ScopedTransaction () { try { rollback(); } catch(...) { } }von uncaught_exception rät er ab.
Gruß
Werner
-
Danke Werner, auf diese Idee bin ich auch schon gekommen. Ich meine, dass sie nicht funktioniert hat und habe geglaubt, dass das iwie mit dem Stack Unwinding zu tun hat. Muss ich vllt doch noch mal genauer untersuchen.