如何创建全局参数对象

时间:2009-07-08 17:12:47

标签: c++ configuration global-variables

这是一项常见而简单的任务:从配置文件中读取配置设置,将设置(例如,作为哈希)保存在对象中,从需要访问配置参数的各种对象访问此对象。

我发现this implementation用于ConfigFile类实现,它可以工作。我的问题是:什么是从我的其他类中提供此类的实例并且是线程安全的最佳方法,避免静态初始化命令惨败等。

我目前的方法是使用

在main()中构建它
    // 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);
}

然后将参数设为全局变量。但我也读到应该使用单例而不是全局变量。如何使用文件名实例化单例?

这一定是一项常见的任务,我认为必须有一个普遍接受的好方法吗?如果有人能指出我,我将不胜感激。

谢谢, ç

6 个答案:

答案 0 :(得分:6)

如果您打算自己动手,我建议您使用Singleton设计模式进行配置。 让类本身存储一个自己类型的静态指针,构造函数是私有的,因此会强制使用静态getter来获取类的一个实例。

所以一个模型(可能无法编译,缺少有趣的Config功能,但应说明一点)

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

如果我不清楚,getConfig()将查看m_configInstance。如果它不是有效的,那么它将创建一个(可以访问私有构造函数)并将其存储在m_configInstance中,以便每个后续调用都可以访问同一个。

所以你的main()将使用setConfigFileName(),然后任何类只需要调用Config :: getConfig()然后调用它上面的操作。比标准的全局变量更清洁。

爆炸 - 在我写这篇文章的时候,其他人也提出了单身设计模式。好吧 - 希望额外的解释有所帮助。

答案 1 :(得分:2)

你看过Boost's Program Options图书馆吗?

答案 2 :(得分:2)

我为配置类所做的是创建一个带有哈希表缓存的单例静态类。我的配置文件旨在读取和写入以更改应用程序设置。

每当调用一个设置时,我都会对哈希表执行查找,如果不存在,那么我从文件中读取设置,锁定哈希表,然后将其放入哈希表中。散列表的查找速度非常快。

答案 3 :(得分:2)

通过提到“静态初始化顺序惨败”,我假设你需要配置项来初始化一些静态对象。单例ConfigFile类可以工作,但您必须更改获取文件名的方式,因为在main()启动之前需要信息。您需要另一个单例来提供文件名,或者在配置类本身中构建文件名。

答案 4 :(得分:0)

我同意克里斯,使用单身人士。关于单例模式的好处是它只在你第一次尝试访问它时初始化/收集你需要的数据,从那里开始它对所有感兴趣的人都可用。如果要允许配置更改,则需要锁定编写器。

答案 5 :(得分:0)

我使用了类似于单例设计模式的技术来配置像这样的全局资源。

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;

构造函数测试m_configInstance未设置,如果是,则抛出异常。然后,它通过将m_configInstance设置为this来完成构造并进行自我注册。

getConfig方法返回实例或抛出异常(如果未设置)。

析构函数再次将m_configInstance设置为0。

要在main()的开头使用该类构造一次。然后在getConfig()方法需要时访问它。

现在Config对象的生命周期被完全控制,与单身人士不同。这对单元测试有额外的好处,每个测试或测试套件都可以创建自己的Config对象,并且它们在测试之间都可以很好地清理。