Re: static member initialization in a try/catch block?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, 2010-06-04 at 12:55 -0400, Bernd Prager wrote:
> All,
> 
> I am trying to design a cache object (singleton) that gets the desired 
> object directly from the database if it is not already in the cache.
> 
> The db connection is a static class member:
> 
> Cache.h:
> class Cache {
>      static log4cxx::LoggerPtr logger;
>      static pqxx::connection dbCon;
> public:
>     ...
> }
> 
> The connection is going to be initialized in the source file Cache.cpp 
> before the class methods:
> 
> ...
> pqxx::connection
>      Cache::dbCon("user=postgres password=xxxx dbname=mydb 
> hostaddr=127.0.0.1 port=5432");
> 
> Cache::Cache() { ... }
> ...
> 
> The connection constructor could throw an exception. How do I catch that?
> Java allows a static block to handle that, C++ AFAIK doesn't.
> I was googleing it but could not find anything; neither in FAQ's. Its 
> probably trivial so please be nice to me. ;-)
The first rule of catching an exception is "don't catch what you don't
know how to handle" - so let me ask this: assuming the database
connection constructor fails, what are you going to do about it? As I
see it, you really have 3 choices: you terminate the program, as your
cache objects cannot work, or you retry some number of times and hope it
succeeds (and if it doesn't, you are right back to square one), or you
design your cache objects so they can live without this connection
(which, seeing as this is the whole point of the class, is unlikely).

It looks to me like you are violating one of the basic guarantees of the
language: that a static object SHALL be initialized (correctly) before
main().

I'd suggest making your DB connection be something that can be staticly
initialized to a known (but not necessarily ready) state, and having
your cache objects handle the DB connection in their constructors:

Cache::Cache() 
{
   try
   {
      Init_db_connection();
   }
   catch(DB_Error_type errvar)
   {
      // appropriate error handling goes here
   }
}

(I'd make the setup of the DB connection its own member function, so
that if you have multiple constructors you can share the code.)

That way, when you attempt to construct a cache object and the
connection fails, you can either work around it,or at least let the
entity constructing the object know there was a problem (I'd suggest
throwing an appropriate error out of the constructor in the case you
cannot work around the problem).

Over the years I've found that having non-trivial constructors for
static objects is A Bad Idea, as you start to introduce all sorts of
issues (constructor order is not fully guaranteed for statics, you may
try to access library functions that aren't guaranteed ready until
main(), etc.). I've found it's best to make static constructors simple,
and then handle anything complex later. 



[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux