Приветствую Вас Гость | RSS

ALLDev

Суббота, 21.12.2024, 18:49
Главная » Статьи » Программирование » C/C++/C#

Сериализация boost::serialization (в контексте Qt)
Есть туториал на официальном сайте.

И все бы хорошо, если не множество подводных камней.

Все началось с того, что я пропустил в туториале объявления макросов (T — идентификатор класса):

BOOST_SERIALIZATION_ASSUME_ABSTRACT(T) — для сериализации абстрактных классов (я объявлял его до определения функций сериализации).

BOOST_SERIALIZATION_SPLIT_FREE(T) — если определять сериализацию через save/load — этот макрос для non intrusive версии сериализации, для intrusive (т.е. метод класса) BOOST_SERIALIZATION_SPLIT_MEMBER(). Объявляется после определения функций сериализации. Назначение — генерирует инлайн функцию serialize, которая используется при (де)сериализации для выбора save/load. Запись и чтение в boost::serialization реализованы через один оператор & (амперсанд) который в зависимости от архива, к которому применяется (ахив то шаблонный надо объявлять) интерпретируется как оператор записи или чтения.

BOOST_CLASS_EXPORT(T) — лучше всего писать для всех производных классов, нужен для сериализации через указатель на базовый класс. Иначе получем exception unregistered class. Смотрите объяснение и подробности.

Также можно напоротся на следующие очевидные грабли: например, если сериализовал QPoint как запись x и y, а потом пытаешься десериализовать точку чтением этих x и y из архива, получишь не те результаты, а может и рантайм эррор — так как пропускаешь чтение информации о типе QPoint.

В заголовке я написал в контексте Qt. Оказывается, что если попытаться сериализовать какой-либо из стандартных классов Qt, получаем ошибку компиляции — can not access private member T::T, что означает — коструктор класса объявлен в секции private. Решение проблемы — перенести макрос Q_DISABLE_COPY в исходниках этого класса из private в public. Смотрите подробности.

Также сильно раздражает абсурдное следование правилам ООП везде где это возможно в Qt, а именно: инкапсуляция данных для элементарных классов (практически структур) — QPointF и QRectF. Если бы я мог обратиться к их полям, кода получилось бы раз в 5 меньше. Нет, я должен разбивать функцию serialize на load и save, которые отличаются только тем, что в одной функции
double x = point.x();
ar & x;

а в другой
double x;
ar & x;
point.setX(x);

В примере выше я не могу написать
ar & point.x();
так как почему-то нельзя использовать вычисляемые выражения (ошибка компиляции), заключение в скобки не помогает. Однако можно записать выражение вида
ar & x & y;

NB: нельзя сериализовать qreal, его надо привести к double, причем таким образом
double x = point.x();
ar & x;

а не
ar & double (point.x());

Дебаг сериализации неприятен

Пример определения сериализации

И применение ее в коде

В целом, результатом остался доволен. Код получился относительно простой и даже быстрый, вся реализация уместилась в отдельном .h файле. Сериализация 1 миллиона инстансов производного класса QGraphicsLineItem прошла за 4,7 секунды (на моем AMD Athlon X2 QL-65) и сгенерировала файл размером 3.8 мб при сериализации в текстовый поток. Минусы — трудно дебажить, однако спасает множество исключений на рантайм ошибки. Также сам код библиотеки boost::serialization снабжен комментариями типа
//если вы здесь получаете ошибку компиляции, значит serialize уже определен как метод этого класса

В интернетах полно негативных отзывов о boost::serialization, кто-то говорит что она медленная, кто-то недоволен отсутствием контроля версий класса. Однако это отзывы о старых версиях, в версии boost 1.52.0 (которая использовалась в этом обзоре) есть контроль версий класса и производительность на мой взгляд удовлетворительная.
Категория: C/C++/C# | Добавил: artkil (12.11.2012)
Просмотров: 2733 | Комментарии: 2 | Теги: Qt, serialization, Boost, c++ | Рейтинг: 0.0/0
Всего комментариев: 0
Имя *:
Email *:
Код *: