Boost Serialization: переход от версионного класса к object_serializable

TLDR: я хотел бы перевести сериализацию класса с уровня реализации object_class_info на object_serializable, сохраняя совместимость со старыми файлами данных и всегда записывая файлы в новом формате.

Обоснование: когда я начал использовать библиотеку Boost Serialization, я не знал, что она уже поставляется с заголовком (complex.hpp), чтобы сериализовать std::complex<double>. Вместо этого я написал свою собственную автономную функцию сериализации:

namespace boost { namespace serialization {
  template<class Archive, typename T>
  void serialize(Archive& ar, std::complex<T>& comp, const unsigned int version) {
    ar & reinterpret_cast<T(&)[2]>(comp)[0];
    ar & reinterpret_cast<T(&)[2]>(comp)[1];
  }
}

Это по умолчанию включает отслеживание информации о версии и классе, что немного замедляет код. Функция сериализации, которая поставляется с Boost, работает немного быстрее.

Теперь я хотел бы перейти на использование версии Boost всегда при записи новых файлов данных, но при этом иметь возможность читать старые файлы данных. Чтение новых файлов со старым двоичным файлом не является проблемой.

Проблема в том, что новая сериализация не версионна (очевидно). Кроме того, я даже не представляю, как можно было бы пытаться читать в архиве, используя старую версию кода, и тут же снова записывать его, используя новую версию, поскольку трейты десериализации/сериализации являются глобальными свойствами.

Что было бы лучшим способом: а) прозрачно читать старые и новые файлы, всегда записывая новые файлы, или б) читать старый файл и сразу же записывать его в новом формате?


person Claudius    schedule 25.04.2016    source источник
comment
Чтение новых файлов со старым двоичным файлом не проблема — что это значит   -  person sehe    schedule 25.04.2016
comment
@sehe: я хочу прочитать старые файлы данных с новыми двоичными файлами, скомпилированными из нового кода. Я не хочу считывать новые файлы данных с существующими двоичными файлами из предыдущих версий кода.   -  person Claudius    schedule 25.04.2016


Ответы (1)


Вы можете оставить старую реализацию и использовать ее, если версия файла «старая».

Используйте ускоренную версию сложной сериализации только при сохранении или в том случае, если версия файла «новая».

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

ОБНОВЛЕНИЕ

Пример использования простой оболочки для вызова старого стиля сериализации:

Жить на Coliru

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/complex.hpp>

template <typename T> struct old_format_wrapper {
    T& wrapped;
    old_format_wrapper(T& w) : wrapped(w) {}
};

template <typename T>
old_format_wrapper<T> old_format(T& w) { return {w}; }

namespace boost { namespace serialization {
    template<class Archive, typename T>
        void serialize(Archive& ar, old_format_wrapper<std::complex<T> >& comp, unsigned) {
            ar & reinterpret_cast<T(&)[2]>(comp.wrapped)[0];
            ar & reinterpret_cast<T(&)[2]>(comp.wrapped)[1];
        }
} }

struct IHaveComplexData {
    std::complex<double> data;

    template <typename Ar> void serialize(Ar& ar, unsigned version) {
        switch(version) {
            case 0: { // old
                    auto wrap = old_format(data);
                    ar & wrap;
                }
                break;
            case 1: // new
            default:
                ar & data; // uses boost serialization
                break;
        }
    }
};

int main() {
    {
        boost::archive::text_oarchive oa(std::cout);
        IHaveComplexData o { { 2, 33 } };
        oa << o;
    }

    {
        std::istringstream iss("22 serialization::archive 13 0 0 0 0 2.00000000000000000e+00 3.30000000000000000e+01");
        boost::archive::text_iarchive ia(iss);
        IHaveComplexData o;
        ia >> o;
        std::cout << o.data;
    }
}

Печатает (в зависимости от вашей версии Boost):

22 serialization::archive 13 0 0 0 0 2.00000000000000000e+00 3.30000000000000000e+01
(2,33)

Конечно, теперь вы можете установить BOOST_CLASS_VERSION(IHaveComplexData, 1)

person sehe    schedule 25.04.2016
comment
Я не уверен, что это сработает, поскольку существует много объектов, содержащих этот тип, и оболочки Boost вокруг serialize будут ожидать номер версии. То есть, как я могу сказать Boost, что иногда он ожидает версионный тип, а иногда нет (того же класса!)? - person Claudius; 25.04.2016
comment
Формат сериализации в любом случае является свойством ваших типов. Можете ли вы показать мне пример того, что было бы сложно/утомительно/невозможно? - person sehe; 25.04.2016
comment
Библиотека сериализации Boost обрабатывает большую часть грязного бита, то есть управление версиями классов, имена классов и т. д. Затем она просто вызывает функцию serialize() для класса, который я хочу сериализовать. Проблема в том, что эта версия класса/другие накладные расходы, то есть дополнительная информация, ожидаемая библиотекой Boost, регулируется свойством типа сериализованного класса. Мой вопрос, по сути, заключается в том, как я могу включить/выключить это только в части программы (биты загрузки). - person Claudius; 25.04.2016
comment
Wat. Просто установите последнюю версию или сериализацию, например. BOOST_CLASS_VERSION(bus_route, 1). - person sehe; 25.04.2016
comment
Но я хочу переключиться с версионной сериализации std::complex (уровень реализации object_class_info) на неверсионную сериализацию (уровень реализации object_serializable), см., например, boost.org/doc/libs/1_59_0/ библиотеки/сериализация/doc/ - person Claudius; 25.04.2016
comment
Ну давай же. Ты говорил мне это несколько раз. Я спросил вас, почему вы не можете просто переключить метод на основе версии окружающего объекта. Возможно, вы можете показать, а не ---рассказать--- повторить - person sehe; 25.04.2016
comment
Уровень реализации — это признак типа сериализованного класса. Эту черту типа нельзя просто переключить для поддержки уровня реализации object_class_info во время загрузки и уровня реализации object_serializable при сохранении, так как это константа времени компиляции. Если каким-то образом это возможно, и вы знаете, как это сделать, пожалуйста, просветите меня, но я должен признать, что я чувствую, что это не особенно продуктивно. - person Claudius; 25.04.2016
comment
Конечно. Я не уверен, почему я должен это делать, просто потому, что вы этого не видите. Позвольте мне добавить образец. - person sehe; 25.04.2016
comment
Хм, спасибо! Мне и в голову не пришло использовать оболочку класса для выбора нужной реализации! Он по-прежнему требует, чтобы класс-оболочка (IHaveComplexData) был правильно версионирован, но кажется не совсем невозможным добавить его везде, где это необходимо. Еще раз спасибо! :) - person Claudius; 25.04.2016