这是一项常见而简单的任务:从配置文件中读取配置设置,将设置(例如,作为哈希)保存在对象中,从需要访问配置参数的各种对象访问此对象。
我发现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);
}
然后将参数设为全局变量。但我也读到应该使用单例而不是全局变量。如何使用文件名实例化单例?
这一定是一项常见的任务,我认为必须有一个普遍接受的好方法吗?如果有人能指出我,我将不胜感激。
谢谢, ç
答案 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
对象,并且它们在测试之间都可以很好地清理。