7

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

我为 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);
}

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

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

谢谢, C

4

6 回答 6

6

如果您要自己动手,我建议您对配置类使用单例设计模式。让类本身存储一个自己类型的静态指针,并且构造函数是私有的,因此将被迫使用静态 getter 来获取该类的一个实例。

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

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() 然后调用它的操作。比标准的全局变量干净得多。

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

于 2009-07-08T17:43:37.440 回答
2

你看过Boost 的程序选项库吗?

于 2009-07-08T17:17:29.740 回答
2

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

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

于 2009-07-08T17:31:27.310 回答
2

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

于 2009-07-08T18:02:36.967 回答
0

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

于 2009-07-08T17:40:54.390 回答
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对象,并且它们在测试之间都被很好地清理了。

于 2009-07-09T17:47:56.247 回答