views:

234

answers:

6

Hi,

Here's a common, simple task: Read configuration settings from a configuration file, save the settings (e.g. as a hash) in an object, access this object from various objects that need to access the configuration parameters.

I found this implementation for the ConfigFile class implementation and it works. My question is: what is the best way to make an instance of this class available from my other classes and be thread safe, avoid static initialization order fiasco, etc.

My current approach is to construct it in main() using

    // Read face detection related parameter values from the configuration file.
string configFileName = "detection_parameters.txt";
try {
 parameters = ConfigFile( configFileName );
}
catch(ConfigFile::file_not_found) {
 cerr << "configuration file not found: " << configFileName << endl;
 exit(-1);
}

and then make parameters a global variable. But I also read that singletons should be used instead of global variables. How can the singleton be instantiated with the file name?

This must be such a common task that I think there must be a generally accepted good way of doing it? I would appreciate if someone can point me to it.

Thanks, C

+1  A: 

Have you looked at Boost's Program Options library?

Kristo
The boost PO library handles command line program options, my question was about configuration options to be read from a file.
recipriversexclusion
You can read from a config file with that library.
Kristo
+2  A: 

What I have done for my configuration class is to create a singleton static class with a hashtable cache. My configuration file is designed to be read and written to for changing application settings.

Whenever a call is made to pull a setting, I perform a lookup on the hashtable, if it's not there, then I read the setting from the file, lock the hashtable, and put it into the hashtable. The hashtable very fast for lookups.

Chris Thompson
A: 

I agree with Chris, use a singleton. The nice thing about the singleton pattern is that it only initializes/gathers the data you need the first time you try to access it, from there on out it is available to everybody that is interested. If you are going to allow the configuration to change you will want to lock the writer.

+3  A: 

If you're going to roll-your-own, I would recommend using the Singleton design pattern for your configuration class. Have the class itself store a static pointer of its own type, and the constructor be private so one would be forced to use the static getter to get the one instance of the class.

so a mock-up (that may not compile, an is missing the fun Config functionality, but should illustrate the point)

class Config
{
public:
   static Config * getConfig();
   static void setConfigFileName(string filename);
private:
   Config();
   static string m_filename;
   static Config * m_configInstance;
};

In case I'm not being clear, the getConfig() would look at m_configInstance. If it isn't a valid one, then it would create one (has access to the private constructor) and store it in m_configInstance so every subsequent call would access the same one.

So your main() would use setConfigFileName(), then any class would just have to call Config::getConfig() and then call the operations on it. A lot cleaner than a standard global variable.

Blast - in the time I spent writing this, other people have suggested the singleton design pattern too. Ah well - hope the additional explanation helps.

Marc
+2  A: 

By mentioning the "static initialization order fiasco", I assume you need to have configuration items available to initialize some static objects. A singleton ConfigFile class will work, but you have to change the way you obtain the filename as the information is needed before main() is started. You'll need another singleton to provide the filename, or build the filename into the configuration class itself.

Mark Ransom
A: 

I have used a technique similar to the singleton design pattern to configure global resources like this.

class Config
{
public:
   Config(const string & filename) {
      if (m_configInstance) {
         throw AlreadyInitException;
      }
      // do main init
      m_configInstance = this;
   }

   ~Config() {
      m_configInstance = 0;
   }

   static Config * getConfig() {
      if (!m_configInstance) {
         throw NoConfigException;
      }
      return m_configInstance;
   }

private:
   static Config * m_configInstance;
};

Config * Config * m_configInstance = 0;

The constructor tests that m_configInstance is not set, if it is it throws an exception. Then it finishes contruction and registers itself by setting m_configInstance to this.

The getConfig method returns the instance or throws and exception if it is not set.

The destructor sets the m_configInstance to 0 again.

To use the class construct it once in the start of main(). Then access it when required by the getConfig() method.

Now the lifetime of the Config object is cleanly controlled, unlike a singleton. And this has an added benefit for unit tests, each test or suite of tests can create there own Config object and they are all nicely cleaned up between tests.

iain