全局配置的最佳实践
Best practice for a global config
我有几个 c++ 程序都在读取 /etc/foo/config.yml
中的 YAML 配置文件。我写了一个从文件中读取配置的函数
YAML::Node load_config();
(使用 yaml-cpp
库)。
我希望这个配置被加载一次,在我程序的 main()
函数的开头,然后 到处都可以访问 作为某种全局变量.
目前,我的许多函数都有 额外的 参数,这些参数只是从配置文件中读取的值。通过全局配置可以避免这种情况,使我的函数定义和调用更加简单易读。
旁注:我还使用 OpenMP 进行分布式计算,这意味着配置必须可供所有并行进程访问。
有人可以举一个小例子来说明如果以正确的方式完成会是什么样子吗?
谢谢!
这是一种方法。这是 schwartz 计数器管理全局单例(例如,std::cout
本身)
的想法的变体
// globals.hpp
#include <istream>
struct globals_object
{
globals_object()
{
// record number of source files which instanciate a globals_object
++init_count_;
}
~globals_object()
{
// The last source file cleans up at program exit
if(--init_count_ == 0)
{
if (pimpl_)
{
delete pimpl_;
}
}
}
// internal implementation
struct impl
{
void load(std::istream& is)
{
// do loading code here
}
int get_param_a() const {
return a_;
}
int a_;
};
// (re)load global state
void load(std::istream&& is)
{
if (pimpl_) delete pimpl_;
pimpl_ = new impl;
pimpl_->load(is);
}
// public parameter accessor
int get_param_a() const {
return get_impl().get_param_a();
}
private:
static int init_count_;
static impl* pimpl_;
static impl& get_impl()
{
return *pimpl_;
}
};
// one of these per translation unit
static globals_object globals;
// globals.cpp
// note - not initialised - will be zero-initialised
// before global constructors are called
// you need one of these in a cpp file
int globals_object::init_count_;
globals_object::impl* globals_object::pimpl_;
// main file
// #include "globals.hpp"
#include <fstream>
int main()
{
globals.load(std::ifstream("settings.yml"));
}
// any other file
// #include "globals.hpp"
#include <iostream>
void foo()
{
std::cout << globals.get_param_a() << std::endl;
}
我有几个 c++ 程序都在读取 /etc/foo/config.yml
中的 YAML 配置文件。我写了一个从文件中读取配置的函数
YAML::Node load_config();
(使用 yaml-cpp
库)。
我希望这个配置被加载一次,在我程序的 main()
函数的开头,然后 到处都可以访问 作为某种全局变量.
目前,我的许多函数都有 额外的 参数,这些参数只是从配置文件中读取的值。通过全局配置可以避免这种情况,使我的函数定义和调用更加简单易读。
旁注:我还使用 OpenMP 进行分布式计算,这意味着配置必须可供所有并行进程访问。
有人可以举一个小例子来说明如果以正确的方式完成会是什么样子吗?
谢谢!
这是一种方法。这是 schwartz 计数器管理全局单例(例如,std::cout
本身)
// globals.hpp
#include <istream>
struct globals_object
{
globals_object()
{
// record number of source files which instanciate a globals_object
++init_count_;
}
~globals_object()
{
// The last source file cleans up at program exit
if(--init_count_ == 0)
{
if (pimpl_)
{
delete pimpl_;
}
}
}
// internal implementation
struct impl
{
void load(std::istream& is)
{
// do loading code here
}
int get_param_a() const {
return a_;
}
int a_;
};
// (re)load global state
void load(std::istream&& is)
{
if (pimpl_) delete pimpl_;
pimpl_ = new impl;
pimpl_->load(is);
}
// public parameter accessor
int get_param_a() const {
return get_impl().get_param_a();
}
private:
static int init_count_;
static impl* pimpl_;
static impl& get_impl()
{
return *pimpl_;
}
};
// one of these per translation unit
static globals_object globals;
// globals.cpp
// note - not initialised - will be zero-initialised
// before global constructors are called
// you need one of these in a cpp file
int globals_object::init_count_;
globals_object::impl* globals_object::pimpl_;
// main file
// #include "globals.hpp"
#include <fstream>
int main()
{
globals.load(std::ifstream("settings.yml"));
}
// any other file
// #include "globals.hpp"
#include <iostream>
void foo()
{
std::cout << globals.get_param_a() << std::endl;
}