const配置结构的正确性

时间:2013-09-26 20:57:19

标签: c++

我有一个配置文件,可以在我的程序运行时开始读入,解析并放入结构中。

我遇到的问题是我希望这些结构保持不变,因为它们中的值在程序生命周期内不应该改变。

目前我正在做以下事情:

的config.h

#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;

config.cpp

/*-- 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

4 个答案:

答案 0 :(得分:2)

与往常一样,你能做的最好的事情就是不重新实现已经写好的东西。有大量的库和框架可以帮助进行c ++的序列化:

理想情况下,您选择的序列化框架将完全重新创建您尝试存储的数据图。无论您是否进行过任何修正,您的目标都可能是仅提供对全局配置数据的const访问。只需确保mutator(包括非const指针)不通过头文件公开。

答案 1 :(得分:1)

这不是您的问题的答案,只是对您的代码的一些观察。

  • 您不需要typedef struct SerialNode { ... } SerialNode;,这是一个成语。在中,您只需撰写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();
// ...