Главная  /  Правка  /  История  /  Логин  /  Область пользователей

Сериализация

Введение

Часто требуется сохранить некоторые объекты C++ в хранилище данных какого-то типа, вроде пользовательской сессии или кэша и извлечь их обратно.

Это нетривиальная задача для C++ - нерефлексивного языка. Поэтому CppCMS обеспечивает простую библиотеку сериализации, которая помогает нам выполнять такие задачи.

Инструменты Сериализации CppCMS

Подготовка Объектов

Предположим, у нас есть класс person, содержащий некоторую информацию и список его потомков - классы child.

Человек:

  1. struct person {  
  2.     std::string name;  
  3.     std::string family;  
  4.     std::string occupation;  
  5.     std::string martial_state;  
  6.     double salary;  
  7.     physical parameters;  
  8.     std::list<child> children;  
  9.     std::vector<std::string> friends;  
  10. };  

Потомок:

  1. struct child {  
  2.     std::string name;  
  3.     physical parameters;  
  4. }  

Физические данные о них:

  1. struct physical {  
  2.     int age;  
  3.     double height;  
  4. };  

Теперь, чтобы сериализовать наш объект, мы можем наследовать его от класса cppcms::serializable. Добавьте заголовочный файл <cppcms/serialization.h> и обновите объект так, чтобы:

  1. struct child {  
  2.     ...  
  3. };  
  4. struct person {  
  5.     ...  
  6. };  

стало

  1. struct child : public cppcms::serializable {  
  2.   ...  
  3. };  
  4. struct person : public cppcms::serializable {  
  5.   ...  
  6. };  

Примечание: Так как объект "physical" - POD, мы можем обработать его лучшим образом.

Теперь добавим двум классам выше новый метод, описывающий как их сериализовать:

Потомок:

  1. void serialize(cppcms::archive &a)  
  2. {  
  3.     a & name & cppcms::as_pod(parameters);  
  4. }  

Метод получает в качестве параметра cppcms::archive - объект, способный сохранить/восстановить нужные данные и мы отмечаем каждый элемент: name и parameters.

Примечание: поскольку мы знаем, что parameters - POD-объект, мы используем специальный маркер, описывающий как его скопировать.

Далее делаем то же самое для класса person:

  1. void serialize(cppcms::archive &a)  
  2. {  
  3.     a & name & family & occupation & martial_state  
  4.       & salary & cppcms::as_pod(parameters) & children & friends;  
  5. }  

Замечание:

Объект archive знает, как обращаться со стандартными C++-контейнерами типа std::vector или std::string. Он знает, как сохранить примитивные типы вроде double в виде простых двоичных данных.

Потому, например, т.к. children это std::list<child> и child наследуется от cppcms::serializable, он знает как автоматически справиться с этой ситуацией.

Если Вы используете собственные или нестандартные контейнеры, возможно потребуется специализация класса: cppcms::archive_traits для Вашего конкретного класса.

Сохранение и Восстановление Объектов

Предположим, что std::string buffer - наш контейнер данных.

Таким образом, мы можем сохранить данные в буфер с помощью следующих действий:

  1. person john;  
  2. ...   // проинициализировать его данные  
  3. cppcms::archive a;  
  4. john.save(a);     // сохранить их в архив  
  5. buffer = a.str(); // взять буфер  

Мы можем загрузить их так:

  1. person john;  
  2. cppcms::archive a;  
  3. a.str(buffer);  
  4. john.load(a);  

Это простейший способ сохранения и загрузки данных, но мы рекомендуем использовать чуть более сложное API которое, как увидим позже, даст нам больше возможностей:

Save:

  1. person john;  
  2. ...   // проинициализировать его данные  
  3. cppcms::serialization_traits<person>::save(john,buffer);  

Load:

  1. person john;  
  2. cppcms::serialization_traits<person>::load(buffer,john);  

Использование с Кэшем и Сессиями

Теперь давайте посмотрим, как мы можем использовать инструменты сериализации CppCMS с интерфейсами Кэша и Сессий:

Можем легко закэшировать объекты person следующим образом:

  1. person john;  
  2. if(!cache().fetch_data("john",john)) {  
  3.     init_person(john);  
  4.     cache().store_data("john",john);  
  5. }  

Это бы позволило, например, снизить число сложных запросов к базе данных для некоторых общих данных, которые не обновлялись.

Можем сохранить объекты с помощью сессий:

  1. person me;  
  2. if(session().is_set("me")) {  
  3.   session().fetch_data("me",me);  
  4.   me.salary += 1;  
  5.   session().store_data("me",me);  
  6. }  

Использование Стороннего API Сериализации

Принцип

CppCMS API - простое, быстрое и мощное, но сильно зависит от платформы - оно не позволяет передать один и тот же объект между хостами с различной архитектурой или порядком следования байт, не поддерживает версионность и прочее.

Поэтому, в некоторых случаях может потребоваться использование с CppCMS сторонних API.

Это довольно просто, все что нужно сделать - предоставить специализацию класса serialization_traits - вот в чем и была причина, по которой мы рекомендовали использовать класс serialization_traits, вместо прямого использования cppcms::archive.

Boost.Serialization

Давайте посмотрим, как использовать, например, Boost.Serialization с CppCMS.

Это наш простейший класс, поддерживающий Boost.Serialization:

  1. struct person {  
  2.   
  3.     std::string name;  
  4.     std::string family;  
  5.   
  6.     template<typename Archive>  
  7.     void serialize(Archive &a,unsigned /*version*/)  
  8.     {  
  9.         a & name & family;  
  10.     }  
  11. };  

Давайте определим две небольшие вспомогательные функции для сохранения и загрузки объекта в строку:

  1. template<typename T>  
  2. void load_from_boost(std::string const &src,T &obj)  
  3. {  
  4.     std::stringbuf ss(src);  
  5.     {  
  6.         boost::archive::binary_iarchive oa(ss);  
  7.         oa >> obj;  
  8.     }  
  9. }  
  10.   
  11.   
  12. template<typename T>  
  13. void save_with_boost(T const &obj,std::string &tgt)  
  14. {  
  15.     std::stringbuf ss;  
  16.     {  
  17.         boost::archive::binary_oarchive oa(ss);  
  18.         oa << obj;  
  19.     }  
  20.     tgt=ss.str();  
  21. }  

Теперь все, что нам нужно, это специализация нашего serialization_traits для корректной обработки person:

  1. namespace cppcms {  
  2.     template<>  
  3.     struct serialization_traits<person> {  
  4.         static void save(person const &obj,std::string &tgt)  
  5.         {  
  6.             save_with_boost(obj,tgt);  
  7.         }  
  8.         static void load(std::string const &src,person &obj)  
  9.         {  
  10.             load_from_boost(src,obj);  
  11.         }  
  12.     };  
  13. }  

В дальнейшем можно будет свободно сохранять и загружать объект с помощью CppCMS интерфейса сессии или кэша:

  1. person john;  
  2. if(!cache().fetch_data("john",john)) {  
  3.     init_person(john);  
  4.     cache().store_data("john",john);  
  5. }  

Проект

CppCMS является основой веб-разработки для выполнения ресурсоемких приложений.

Размещение

SourceForge.net Logo

Поддержать проект

CppCMS needs You


Навигация

Главная страница


Валидация CSS | Валидация XHTML 1.0