The presence of a destructor performs different actions depending on whether an exception has occurred

I have code to update a database table that looks like

try { db.execute("BEGIN"); // Lots of DELETE and INSERT db.execute("COMMIT"); } catch (DBException&) { db.execute("ROLLBACK"); } 

I would like to wrap the transaction logic in the RAII class so that I can just write

 { DBTransaction trans(db); // Lots of DELETE and INSERT } 

but how would I write a destructor for it?

+6
c ++ exception raii transactions
source share
4 answers

Use the following:

 transaction tr(db); ... tr.commit(); 

When tr.commit() completes, it sets the state to "commit done", and the destructor does nothing, otherwise it rolls back.

Exception checking is a bad idea, think:

 transaction tr(db); ... if(something_wrong) return; // Not throw ... tr.commit(); 

In this case, you probably expect rollback rather than commit, but the commit will complete.

Edit: but if you still want this bad, look at std::uncaught_exception() , but read this first http://www.gotw.ca/gotw/047.htm

+12
source share

You can use the following logic:

  • Add the boolean commit_done initialized to false for your transaction class.
  • In your constructor, start the transaction.
  • Add a method to commit the transaction and update commit_done .
  • In your destructor, call rollback only if commit_done is still false
+3
source share

By removing exception handling, you are damaging your RAII.

The code should be

 try { DBTransaction trans(db) ; // Lots of DELETE and INSERT // should one fail, a DBTransactionRollback exception will be thrown trans.commit() ; } catch(const DBTransactionRollback & e) { // If really needed, you could extract failure information from "e" } 

Differences with your source code are what motivated my answer:

  • Nothing is needed in "catch": the destructor will consider automatic rollback if the commit () method was not called successfully ( which could, for example, set some DBTransaction private logic element to true ). A trap where the code will continue if the transaction failed.

  • You must create a highlighted exception (I called it DBTransactionRollback) to take a moment in one of your commands. Thus, catch will catch an exception with transactional rollback, and not other exceptions (for example, STL, etc.).

  • Using the exception mechanism allows you to put your code in several functions called from this block of try / catch code, without the need to refer to logical returns and other error codes.

Hope this answers your question.

+2
source share

The easiest way I can imagine is to set the class to exclude a private member variable in the class and test it / perform the corresponding action in the destructor.

+1
source share

All Articles