0

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

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

目前我正在做以下事情:

配置文件

#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

4

4 回答 4

2

与往常一样,您能做的最好的事情就是不要重新实现已经编写好的东西。有大量的库和框架将有助于 C++ 的序列化:

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

于 2013-09-26T21:09:38.950 回答
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已经提供了适当的比较。

于 2013-09-26T21:09:44.467 回答
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++,因此可能存在一些语法错误 :)

于 2013-09-26T21:12:21.517 回答
1

简单的答案是 Thomas 建议的,但做得正确(即不会导致未定义的行为):

创建一个可变配置对象,但通过常量引用将其传递给其余组件。当您创建(以及维护)真实对象时,您可以更改它,但应用程序的其余部分将无法修改配置。我过去使用的一个常见模式是:

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();
// ...
于 2013-09-26T22:06:59.377 回答