boost::serialization与可变成员

4
使用boost::serialization,如何序列化一个包含可变成员中缓存的派生值的对象是最佳的方式?
class Example
{
public:
    Example(float n) : 
        num(n),
        sqrt_num(-1.0)
    {}

    // compute and cache sqrt on first read
    float get_sqrt() const
    { 
        if(sqrt_num < 0) 
            sqrt_num = sqrt(num);
        return sqrt_num;
    }

    template <class Archive> 
    void serialize(Archive& ar, unsigned int version)
    { ... }
private:
    float num;
    mutable float sqrt_num;
};

出于维护方面的考虑,我希望避免将serialize()拆分为单独的save()和load()方法。

一个次优的serialize实现:

    template <class Archive> 
    void serialize(Archive& ar, unsigned int version)
    {
        ar & num;
        sqrt_num = -1.0;
    }

这个处理反序列化的情况,但在序列化的情况下,缓存值被清除,必须重新计算。

在这种情况下,最佳实践是什么?

2个回答

3

将您的保存和加载方法分开并不意味着您必须维护两份序列化代码的副本。您可以将它们分开,然后使用公共函数将它们合并。

private:
  friend class boost::serialization::access;

  BOOST_SERIALIZATION_SPLIT_MEMBER()

  template <class Archive>
  void save(Archive& ar, const unsigned int version) const {
      const_cast<Example*>(this)->common_serialize(ar, version);
  }

  template <class Archive>
  void load(Archive& ar, const unsigned int version) {
      common_serialize(ar, version);
      sqrt_num = -1;
  }

  template <class Archive>
  void common_serialize(Archive& ar, const unsigned int version) {
      ar & num;
  }

您可能已经注意到了const_cast。这是这个想法的一个不幸的限制。尽管serialize成员函数对于保存操作是非const的,但save成员函数需要是const的。只要您正在序列化的对象最初没有被声明为const,就可以像上面展示的那样安全地强制转换它。文档简要提到了需要为const成员进行转换;这是类似的。
通过以上更改,您的代码将正确地打印出“2”作为ex1ex2,并且您只需要维护一个序列化代码副本。load代码仅包含特定于重新初始化对象内部缓存的代码;save函数不会触及缓存。

2
您可以检查Archive::is_loading字段,如果为真,则加载缓存值。
template <class Archive> 
void serialize(Archive& ar, unsigned int version)
{
    ar & num;
    if(Archive::is_loading::value == true)
        sqrt_num = -1.0;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接