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() 方法。

序列化的一种次优实现:

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

这处理了反序列化的情况,但是在序列化的情况下,缓存的值被杀死并且必须重新计算。

在这种情况下,最佳做法是什么?

4

2 回答 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 成员转换的必要性;这是相似的。

通过上面的更改,您的代码将正确地为ex1和打印“2” ex2,并且您只需要维护一份序列化代码的副本。该load代码仅包含特定于重新初始化对象内部缓存的代码;该save功能不会触及缓存。

于 2010-05-18T07:48:11.450 回答
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;
}
于 2013-10-30T20:35:14.660 回答