Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Serialization - More on Archives

Boost , ,

C++ Boost

Serialization

Archive Class Reference


Trivial Archive
More Useful Archive Classes
Usage
Testing
Polymorphic Archives

Trivial Archive

The Archive concept specifies the functions that a class must implement in order to be used to serialize Serializable types. Our discussion will focus on archives used for saving as the hierarchy is exactly analogous for archives used for loading data.

Minimum Requirments

The simplest class which will model the Archive concept specifies the functions that a class will look like:

#include <cstddef> // std::size_t
//////////////////////////////////////////////////////////////
// class trivial_oarchive
class trivial_oarchive {
public:
    //////////////////////////////////////////////////////////
    // public interface used by programs that use the
    // serialization library
    typedef boost::mpl::bool_<true> is_saving; 
    typedef boost::mpl::bool_<false> is_loading;
    template<class T> void register_type(){}
    template<class T> trivial_oarchive & operator<<(const T & t){
        return *this;
    }
    template<class T> trivial_oarchive & operator&(const T & t){
        return *this << t;
    }
    void save_binary(void *address, std::size_t count){};
};
The simplest possible input archive class is analogous to the above. In the following discussion, only output archives will be addressed. Input archives are exactly symmetrical to output archives.

Этот архив будет компилироваться и выполняться с любыми типами, которые реализуют.Сериализируемаяконцепция. Например, см.<demo_trivial_archive.cpp>. Конечно, эта программа не даст никакого результата, как есть. Но он обеспечивает отправную точку для простого класса, который можно использовать для входа в форматированный выход. См. реализацию простого архива журналов, как это было сделано.

Более полезные архивные классы

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

Наши архивы были учтены в дереве классов, чтобы свести к минимуму повторение кода. Это показано на диаграммеклассов. Любой класс, который удовлетворяет следующим требованиям, будет вписываться в эту иерархию и реализовывать все необходимые функции. Происхождение из базового классаcommon_oarchive.hppобеспечивает все функции, которые мы желаем, которые отсутствуют в тривиальном_oarchive выше.<



#include <cstddef> // std::size_t
#include <boost/archive/detail/common_oarchive.hpp>

/////////////////////////////////////////////////////////////////////////
// class complete_oarchive
class complete_oarchive : 
    public boost::archive::detail::common_oarchive<complete_oarchive>
{
    // permit serialization system privileged access to permit
    // implementation of inline templates for maximum speed.
    friend class boost::archive::save_access;
    // member template for saving primitive types.
    // Specialize for any types/templates that require special treatment
    template<class T>
    void save(T & t);
public:
    //////////////////////////////////////////////////////////
    // public interface used by programs that use the
    // serialization library
    // archives are expected to support this function
    void save_binary(void *address, std::size_t count);
};
>При наличии подходящих определений<save>и<save_binary>любая программа, использующая сериализацию с соответствующим компилятором C++, должна компилировать и запускать этот класс архивов.

Опциональные ограничения

Класс<detail::common_oarchive>содержит ряд функций, которые используются различными частями библиотеки сериализации, чтобы помочь сделать архив в определенной форме.

<void save_start(char const *)>

Дефолт: Ничего не делает.
Цель: Вставить/вставить имя объекта в архив. Используется XML-архивом для ввода «» перед данными.

<void save_end(char const *)>

Дефолт: Ничего не делает.
Цель: Вставить/вставить имя объекта в архив. Используется архивом XML для ввода «» после данных.

<void end_preamble()>

Дефолт: Ничего не делает.
Цель: Называетсякаждый раз, когдапользовательские данные сохраняются. Это не называется, когда архивные бухгалтерские данные сохраняются. Это используется архивами XML для определения того, когда вводить символ «>» в конце заголовка XML. XML-архивы сохраняют свой собственный внутренний флаг, указывающий, что записываемые данные являются данными заголовка. Этот внутренний флаг сбрасывается, когда пишется тег запуска объекта. Когда<void end_preamble()>вызывается, и этот внутренний флаг устанавливается, на выход добавляется символ «>», и внутренний флаг сбрасывается. Реализация по умолчанию для<void end_preamble()>- это no-op, что позволяет оптимизировать его для классов архивов, которые его не используют.

< template<class T> void save_override(T & t, int); >

Дефолт:Взывает<archive::save(Archive & ar, t)>
Это основной вход в библиотеку сериализации.
Цель: Это может быть специализировано в тех случаях, когда данные должны быть записаны в архив каким-то особым образом. Например, XML-архивы реализуют специальную обработку для пар имён-значений, переопределяя этот шаблон функций для пар имён-значений. Это заменяет обработку пары имени-значения по умолчанию, которая просто отбрасывает имя, с одной подходящей для XML, которая записывает начало тега XML с правильным именем объекта.

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

Типы, используемые библиотекой сериализации

Библиотека сериализации вводит данные бухгалтерского учета в архив сериализации. Эти данные включают в себя такие вещи, как идентификаторы объектов, номера версий, имена классов и т. Д. Каждый из этих объектов включен в обертку, чтобы класс архива мог переопределить реализацию<void save_override(T & t, int);>. Например, в XML-архиве оверрайд для этого типа делает объект_id равным 23 как «объект_id=_23». В следующей таблице перечислены типы, определенные в<boost::archive namespace>используемой внутри библиотеки сериализации:

[

Все они связаны с последовательностью по умолчанию, определенной в терминах примитивных типов, поэтому не требуется определять<save_override>для этих типов.

Они определены в<basic_archive.hpp>. Всем этим типам присваиваетсяуровень реализации<primitive>и они конвертируются в такие типы, как int, unsigned int и т.д. Это подтверждается<basic_text_iarchive.hpp>. Однако в некоторых случаях для этих типов должны быть явно предусмотрены переопределения. Например, см.<basic_xml_iarchive.hpp>.

На практике мы, вероятно, не совсем справимся. Возможно, потребуется решить один или несколько из следующих вопросов:

  • Многие компиляторы не могут реализовать правильную частичную упорядоченность шаблонов функций. Архивы, включенные в эту библиотеку, работают вокруг этого, используя перегрузку аргументов. Этот метод описан вдругом разделе этого руководства
  • . Даже если мы используем соответствующий компилятор, мы можем захотеть, чтобы наш новый класс архивов был переносим на несоответствующие компиляторы.
  • Наш формат архива может потребовать вставки дополнительной информации. Например, архивы XML нуждаются в...окружающих все объекты данных.
  • Решение любой из вышеперечисленных проблем может привести к возникновению дополнительных проблем.
  • Архивы, включенные в библиотеку, представляют собой шаблоны, которые используют<stream>или<streambuf>в качестве параметра шаблона, а не простые классы. В сочетании с вышесказанным возникает еще больше проблем с несоответствующими компиляторами.
Приложеннаядиаграмма классовпоказывает отношения между классами, используемыми для реализации библиотеки сериализации.

Тщательное изучение архивов, включенных в библиотеку, иллюстрирует, что требуется для создания переносного архива, который охватывает все типы данных.

Использование

Недавно созданный архив обычно хранится в собственном модуле заголовка. Все, что необходимо, это включить заголовок и построить экземпляр нового архива. За исключением одного особого случая.
  • Случаи производного класса сериализуются через указатель базового класса.
  • Такие случаи не регистрируются ни неявно, ни явно. То есть макрос<BOOT_CLASS_EXPORT>используется для инстанцирования кода сериализации для включённых архивов.
Для выполнения этой работы после определения класса архива следует включить следующее.<

#define BOOST_SERIALIZATION_REGISTER_ARCHIVE(Archive)
>Неспособность сделать это не помешает программе правильно составлять, связывать и выполнять, за исключением одного случая. Если экземпляр производного класса сериализуется через указатель на его базовый класс, программа выкинет.<unregistered_class>Исключение.

Испытание

Исчерпывающее тестирование библиотеки требует проверки различных аспектов сериализации объектов с каждым архивом. Существует 46 различных тестов, которые могут работать с любым архивом. В систему включено 5 «стандартных архивов». (3 в системах, не поддерживающих широкий трактор i/o).

Кроме того, существует 28 других тестов, которые не связаны с каким-либо конкретным классом архивов.

Настройка по умолчанию<bjam>будет выполнять все вышеописанные тесты. Это приведет к 46 архивным тестам * 5 стандартных архивов + 28 общих тестов = 258 тестов. Обратите внимание, что полный тест библиотеки будет включать в себя DLL против статической библиотеки, выпуск против отладки, так что фактическая сумма будет ближе к 1032 тестам.

Для каждого архива в тестовом каталоге имеется файл заголовка, аналогичный приведенному ниже. Название этого архива передается в программу тестирования путем установки переменной среды<BOOST_ARCHIVE_TEST>на имя заголовка. Вот файл заголовка<test_archive.hpp>. Файлы заголовков тестов для других архивов похожи.<


// text_archive test header
// include output archive header
#include <boost/archive/text_oarchive.hpp>
// set name of test output archive
typedef boost::archive::text_oarchive test_oarchive;
// set name of test output stream
typedef std::ofstream test_ostream;
// repeat the above for input archive
#include <boost/archive/text_iarchive.hpp>
typedef boost::archive::text_iarchive test_iarchive;
typedef std::ifstream test_istream;
// define open mode for streams
//   binary archives should use std::ios_base::binary
#define TEST_STREAM_FLAGS (std::ios_base::openmode)0
>Чтобы протестировать новый архив, например, переносные двоичные архивы, с помощью компилятора gcc, сделайте заголовок файла<portable_binary_archive.hpp>и вызовите<bjam>с<

-sBOOST_ARCHIVE_LIST=portable_binary_archive.hpp
>. Этот процесс инкапсулируется в оболочке или cmd-скрипте<library_test>, командная строка которого<

library_test --toolset=gcc -sBOOST_ARCHIVE_LIST=portable_binary_archive.hpp
>

Полиморфные архивы

Мотивация

Все архивы, описанные до сих пор, реализуются в виде шаблонов. Код для сохранения и загрузки данных в архивы регенерируется для каждой комбинации класса архива и типа данных. При таких обстоятельствах хороший оптимизирующий компилятор, способный расширить<inline>функции до достаточной глубины, будет генерировать быстрый код. Однако:
  • Много встроенного кода может быть воспроизведено.
  • Если существует несколько классов архивов, код будет регенерироваться для каждого класса архивов.
  • Если код сериализации помещается в библиотеку, эта библиотека должна перестраиваться каждый раз, когда создается новый класс архивов.
  • Если код сериализации помещается в DLL,
    • DLL будет содержать версии кода для каждого известного типа архива. Это приведет к загрузке DLL, которые содержат много кода, который не используется - в основном побеждая одну из основных мотиваций для выбора использования DLL.
    • Если создается новый архив и отправляется приложение, все DLL должны быть восстановлены и перегружены вместе с приложением, которое использует новый архив. Таким образом, другая основная мотивация для использования DLL побеждена.

Осуществление

В этом случае речь идет о паре<polymorphic_oarchive>и<polymorphic_iarchive>. Они представляют общий интерфейс виртуальных функций — никаких шаблонов — что эквивалентно стандартному шаблонному. Это показано на диаграмме классов.

Сопроводительная демо-программа в файлах<demo_polymorphic.cpp>,<demo_polymorphic_A.hpp>и<demo_polymorphic_A>показывает, как следует использовать полиморфные архивы. Примечание:

  • <demo_polymorphic_A.hpp>и<demo_polymorphic_A.cpp>не содержат шаблонов и ссылок на какую-либо конкретную реализацию архива. То есть они должны быть составлены только один раз для всех реализаций архива. Это относится и к архивным классам, созданным в будущем.
  • Основная программа<demo_polymorphic.cpp>указывает конкретную реализацию архива.
Как видно на диаграммеклассаи файлах заголовка, эта реализация представляет собой просто композицию полиморфного интерфейса и стандартной реализации, управляемой шаблоном. Эта композиция выполнена шаблонами<polymorphic_iarchive_route.hpp>и.<polymorphic_oarchive_route.hpp>, которые перенаправляют вызовы в полиморфные архивы в конкретный архив. Поскольку они не содержат кода, специфичного для конкретного архива реализации, они могут быть использованы для создания полиморфной реализации архива из любой функционирующей шаблонной реализации архива.

Для удобства были включены небольшие файлы заголовка, которые содержат<typedef>для полиморфной реализации для каждого соответствующего шаблонного. Например, заголовки<polymorphic_text_iarchive.hpp>и<polymorphic_text_oarchive.hpp>содержат<typedef>для полиморфной реализации стандартных классов текстовых архивов<text_iarchive.hpp>и.<text_oarchive.hpp>соответственно. Все включенные полиморфные архивы используют одну и ту же схему именования.

Использование

Полиморфные архивы решают вопросы, поднятые выше в отношении шаблонной реализации. То есть нет реплицированного кода и нет перекомпиляции для новых архивов. Это приведет к меньшим исполняемым файлам для программ, которые используют более одного типа архива и меньшие DLLS. Существует штраф за вызов функций архива через таблицу отправки виртуальных функций, и нет возможности для компилятора<inline>функций архива. Это приведет к заметному ухудшению производительности для сохранения и загрузки архивов.

Заметим, что понятие полимофических архивов принципиально несовместимо с сериализацией новых типов, помеченных пользователем «примитивными» с:<


BOOST_CLASS_IMPLEMENTATION(my_primitive_type, boost::serialization::primitive_type)
>Код для реализации сериализации для этих типов вводится «на лету» в программе пользователя. Но это противоречит всей цели полиморфного архива. Попытка сериализации такого примитивного типа приведет к ошибке компиляции, поскольку общий полиморхический интерфейс статичен и не может создавать код для нового типа.

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


© CopyrightRobert Ramey2002-2004. Распространяется под лицензией Boost Software License, версия 1.0. (См. сопроводительный файл LICENSE_1_0.txt или копию по адресу http://www.boost.org/LICENSE_1_0.txt)

Статья Serialization - More on Archives раздела может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-20 18:54:46/0.0075349807739258/0