boost :: сериализация с изменяемыми членами - PullRequest
4 голосов
/ 18 мая 2010

Используя 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;
    }

Это обрабатывает случай десериализации, но в случае сериализации кэшированное значение уничтожается и должно быть пересчитано.

Какая лучшая практика в этом случае?

Ответы [ 2 ]

3 голосов
/ 18 мая 2010

Разделение методов сохранения и загрузки не означает, что вам нужно хранить две копии кода сериализации. Вы можете разделить их, а затем снова присоединить к ним с помощью общей функции.

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 неконстантна для сохранения операций, функция-член save должна быть константной. Пока объект, который вы сериализуете, изначально не был объявлен как const, его безопасно отбрасывать, как показано выше. В документации кратко упоминается необходимость разыгрывания константных членов ; это похоже.

С учетом вышеуказанных изменений ваш код будет правильно печатать «2» как для ex1, так и для ex2, и вам потребуется только одна копия кода сериализации. Код load содержит только код, специфичный для повторной инициализации внутреннего кэша объекта; функция save не затрагивает кеш.

2 голосов
/ 31 октября 2013

Вы можете проверить поле 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;
}
...