使用特定于环境的状态

时间:2015-06-20 09:06:01

标签: c++ serialization boost boost-serialization

我有一些看起来像这样的课程:

class Base {
public:
    virtual ~Base() {}
    ...
};

class Derived1 {
    OuterState1& outerState;
    InnerState1 innerState;
    ...
    template <typename Ar>
    void serialize(Ar& ar, const unsigned int /*version*/) {
        ar & innerState;
    }
public:
    Derived1(OuterState1& outerState) : outerState(outerState) {}
    ...
};

class Derived2 {
    OuterState2& outerState;
    InnerState2 innerState;
    ...
    template <typename Ar>
    void serialize(Ar& ar, const unsigned int /*version*/) {
        ar & innerState;
    }
public:
    Derived1(OuterState2& outerState) : outerState(outerState) {}
    ...
};

基本上,类的状态取决于外部环境,我不想序列化它。对于不同的子类,该状态可能不同。我想序列化这个类。一个好处是boost :: serialization可以很好地处理多态类,但在我看来这对我来说还不够好。我可以找到以下方法来序列化这些对象,我不喜欢它们:

  1. 对外部状态使用全局变量。现在我们要么在类中使用这些全局变量,要么重载load_construct_data()并从这个全局变量创建对象。这个解决方案的问题在于它需要全局变量,这通常是一个糟糕的设计,并且如果程序需要处理多个这样的状态,则会中断。

  2. 不要使用Boost的多态序列化功能。而是将实际类型保存在枚举中,然后以非多态方式保存对象。加载时,加载类型枚举,然后在开关中创建具有适当外部状态的相应类型的对象,然后以非多态方式加载对象。这样做的问题是我必须做很多手动编码,这些编码会由Boost自动完成,如果我想序列化这些对象的集合,它就不起作用。

  3. 这个问题有更好,更优雅的解决方案吗?

1 个答案:

答案 0 :(得分:0)

解决方案是将特定于环境的状态保存为类中的指针。然后在实际类之前将其保存/加载到存档中,并修改其值。所以基类的序列化看起来像这样:

class Derived1 {
    OuterState1& outerState;
    InnerState1 innerState;
    ...
    template <typename Ar>
    void serialize(Ar& ar, const unsigned int /*version*/) {
        ar & innerState;
    }
public:
    Derived1(OuterState1& outerState) : outerState(outerState) {}
    const OuterState1& getOuterState() const { return outerState; }
    ...
};

    template <typename Ar>
    void save_construct_data(Ar& ar, const Derived1* object, const unsigned int /*version*/) {
        ar << &object.getOuterState();
    }

    template <typename Ar>
    void load_construct_data(Ar& ar, Derived1* object, const unsigned int /*version*/) {
        OuterState1* state;
        ar >> state;
        ::new(object)Derived1{*state};
    }

将环境特定对象序列化为NOP。

template <typename Ar>
void serialize(Ar&, OuterState1&, const unsigned int) {
}

保存时,请执行以下操作:

OuterState1 outerState1;
OuterState2 outerState2;
std::shared_ptr<Base> object = getObject();
...
// saving starts now
archive << outerState1 << outerState2 << object;
...

加载时,加载状态,然后覆盖它们。假设outerState1outerState2位于与之前相同的位置,并且已经具有新的期望值。

std::shared_ptr<Base> object;
archive >> outerState1 >> outerState2 >> object;

另一方面,问题中提供的代码并不完整。需要完成基类序列化,但现在已经完成了这一点。