我有一个配置文件,可以在我的程序运行时开始读入,解析并放入结构中。
我遇到的问题是我希望这些结构保持不变,因为它们中的值在程序生命周期内不应该改变。
目前我正在做以下事情:
#pragma warning(push)
#pragma warning(disable: 4510) /*-- we don't want a default constructor --*/
#pragma warning(disable: 4610) /*-- we don't want this to ever be user instantiated --*/
typedef struct SerialNode {
private:
void operator=(SerialNode&);
public:
const char* const port;
const char* const format;
} SerialNode;
#pragma warning(pop)
typedef std::map<const char*, const SerialNode*, MapStrComp> SerialMap;
SerialMap SerialConfig;
/*-- so we don't fall out of scope --*/
SerialNode* global_sn;
SerialNode local_sn = {port, format};
global_sn = new SerialNode(local_sn);
SerialConfig[key_store] = global_sn;
这很好用。但是我的问题是,现在我正在处理更复杂的配置数据,这需要我将结构从列表中拉回来,修改它然后再将它放回去。
显然我无法修改它,所以解决方案就像:
SerialNode* global_sn;
SerialNode* old_sn = SerialConfig[key_store];
SerialNode local_sn = {port, format, old_sn->old_data, old_sn->more_old_data};
global_sn = new SerialNode(local_sn);
SerialConfig[key_store] = global_sn;
delete old_sn;
但这让我觉得糟糕的编程习惯。是否有更好的方法来实现我的目标,而不需要这样的黑客解决方案?
供参考,我正在使用Visual Studio 2010
答案 0 :(得分:2)
与往常一样,你能做的最好的事情就是不重新实现已经写好的东西。有大量的库和框架可以帮助进行c ++的序列化:
理想情况下,您选择的序列化框架将完全重新创建您尝试存储的数据图。无论您是否进行过任何修正,您的目标都可能是仅提供对全局配置数据的const访问。只需确保mutator(包括非const指针)不通过头文件公开。
答案 1 :(得分:1)
这不是您的问题的答案,只是对您的代码的一些观察。
您不需要typedef struct SerialNode { ... } SerialNode;
,这是一个c成语。在c++中,您只需撰写struct SerialNode { ... };
并使用SerialNode
作为类型名称。
如果要阻止默认构造函数,请将其设置为私有,就像使用赋值运算符一样
class SerialNode {
private:
SerialNode();
SerialNode &operator=(SerialNode&);
...
};
请勿使用char*
成员,而是使用std::string
。使用C ++字符串比普通char
指针和相关的堆分配更容易,更安全。
同样适用于map
密钥;如果您使用std::string
作为密钥,则不再需要MapStrComp
,因为std::string
已经提供了适当的比较。
答案 2 :(得分:1)
可能更好的是将整个事物包装在一个单独的类中:
class Config {
public:
static Config const& get() { return *config; }
static void load();
SerialNode const* operator[](const char*);
private:
static Config* config;
SerialMap map;
};
void Config::load() {
config = new Config();
// put things into it
}
免责声明:未经过测试,并且暂时没有使用过C ++,因此可能存在一些语法错误:)
答案 3 :(得分:1)
简单的答案是托马斯建议的,但是正确地完成了(也就是说,没有导致未定义的行为):
创建一个可变配置对象,但通过常量引用将其传递给其余组件。当您创建(以及维护)真实对象时,您可以更改它,但应用程序的其余部分将无法修改配置。我过去常用的一种模式是:
class SomeObject {
Configuration const & config;
public:
SomeObject(Configuration const & config) : config(config) {}
void f() {
if (config.someParam()) { ...
// ...
void loadConfiguration(Config & config) { ... }
int main() {
Configuration config;
loadConfiguration(config); // config is a non-const &, can modify
SomeObject object(config); // object holds a const&, can only read
object.f();
// ...