Artyom
Artyom

Reputation: 31233

Use of uncaught_exception to handle error conditions

I have following problem.

I have database connection that are recycled (put back into pool).

For example:

{
 session sql(conn_str); // take connection from pool

 sql.exec("insert into ...")
} // at the end of the scope return connection to pool

However in certain cases recycling may be wrong - for example disconnect, or some other significant error.

So I want to automatically prevent from the connection being recycled. I want to implement following technique using std::uncaught_exception - so the exec() function would detect exceptions and prevent recycling:

session::exec(...)
{
   guard g(this)

   real_exec(...);
}

Where guard:

class guard {
public:
   guard(session *self) : self_(self) {}
   ~guard() {
      if(std::uncaught_exception()) {
        self->mark_as_connection_that_should_not_go_to_pool();
      }
   }
}

Now, I'm aware of http://www.gotw.ca/gotw/047.htm that does not recommend using std::uncaught_exception on the other case I don't see any wrong with my code also, the provides examples discussed.

Are there any possible problems with this code.

Note:

  1. I want this change to be non-intrusive so that SQL backend would be able to throw and not check for every case if it is critical or not.
  2. I don't want user to take any action about it so it would be transparent for him.

Upvotes: 1

Views: 221

Answers (1)

Mark Ransom
Mark Ransom

Reputation: 308158

I don't see any advantage to your method over something more straightforward:

session::exec()
{
    try
    {
        real_exec();
    }
    catch(...)
    {
        mark_as_connection_that_should_not_go_to_pool();
        throw;
    }
}

If the verboseness of this solution bothers you, I will note that they haven't ripped macros out of C++ yet. I wouldn't prefer this version as it masks the underlying code and is kind of ugly.

#define GUARD try {
#define ENDGUARD } catch(...) { mark_as_connection_that_should_not_go_to_pool(); throw; }

session::exec()
{
    GUARD
    real_exec();
    ENDGUARD
}

Another possibility is to assume failure until success is achieved.

session::exec()
{
    mark_as_connection_that_should_not_go_to_pool();
    real_exec();
    mark_as_connection_that_may_go_to_pool();
}

Finally to answer the question of whether uncaught_exception will work as you've outlined, I will quote from Microsoft's documentation of the function:

In particular, uncaught_exception will return true when called from a destructor that is being invoked during an exception unwind.

It appears to do exactly what you'd expect.

Upvotes: 2

Related Questions