Что такое cereal и зачем она нужна?
cereal — это легковесная, header-only библиотека для сериализации данных на языке C++. Она позволяет преобразовывать сложные структуры данных (классы, структуры, контейнеры STL) в такие форматы, как JSON, XML и бинарный формат, а затем восстанавливать их обратно. Это критически важно для сохранения состояния программы, передачи данных по сети, логирования или обмена информацией между разными языками программирования.
В отличие от более тяжеловесных решений (например, Boost.Serialization), cereal не требует предварительной компиляции или сложной настройки. Она полностью состоит из заголовочных файлов, что упрощает интеграцию в любой проект. Основные преимущества:
- Header-only: не нужно собирать библиотеку отдельно.
- Поддержка C++11/14/17: использует современные возможности языка.
- Гибкость: поддерживает пользовательские типы, умные указатели, полиморфизм.
- Производительность: бинарный формат очень быстр и компактен.
Установка
Поскольку cereal — это header-only библиотека, установка сводится к копированию заголовочных файлов в ваш проект. Никаких pip install или npm install для C++ не требуется. Вот два основных способа:
Способ 1: Ручная установка (рекомендуется для обучения)
- Скачайте последнюю версию с GitHub (зелёная кнопка "Code" → "Download ZIP").
- Распакуйте архив.
- Скопируйте папку
include/cerealв папку с вашим проектом. - В коде подключайте:
#include "cereal/cereal.hpp".
Способ 2: Через пакетный менеджер vcpkg
# Установите vcpkg, если ещё не установлен
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
.\bootstrap-vcpkg.bat # Windows
./bootstrap-vcpkg.sh # Linux/macOS
# Установите cereal
.\vcpkg install cereal # Windows
./vcpkg install cereal # Linux/macOS
# Подключите в CMakeLists.txt:
# find_package(cereal CONFIG REQUIRED)
# target_link_libraries(your_project PRIVATE cereal::cereal)
Быстрый старт с примером кода
Давайте создадим простую структуру Person и сериализуем её в JSON. Создайте файл main.cpp:
#include <iostream>
#include <fstream>
#include <string>
#include <cereal/archives/json.hpp>
#include <cereal/types/string.hpp>
struct Person {
std::string name;
int age;
// Обязательный метод для cereal
template<class Archive>
void serialize(Archive& archive) {
archive(name, age);
}
};
int main() {
Person p1{"Alice", 30};
// Запись в файл
{
std::ofstream file("person.json");
cereal::JSONOutputArchive archive(file);
archive(CEREAL_NVP(p1)); // CEREAL_NVP — для именованных полей
}
// Чтение из файла
Person p2;
{
std::ifstream file("person.json");
cereal::JSONInputArchive archive(file);
archive(p2);
}
std::cout << "Name: " << p2.name << ", Age: " << p2.age << std::endl;
return 0;
}
Скомпилируйте: g++ -std=c++11 main.cpp -o main. После запуска появится файл person.json с содержимым {"p1": {"name": "Alice", "age": 30}}.
Основные методы и функции
Ниже приведены ключевые элементы библиотеки. Все примеры предполагают наличие #include <cereal/cereal.hpp> и соответствующих архивов.
1. cereal::JSONOutputArchive
Что делает: Создаёт архив для записи данных в формат JSON.
Параметры: Принимает ссылку на std::ostream (например, std::ofstream или std::ostringstream).
#include <cereal/archives/json.hpp>
#include <sstream>
std::ostringstream oss;
{
cereal::JSONOutputArchive archive(oss);
int value = 42;
archive(value);
}
std::cout << oss.str(); // Выведет: {"value0": 42}
2. cereal::JSONInputArchive
Что делает: Создаёт архив для чтения данных из JSON.
Параметры: Принимает ссылку на std::istream (например, std::ifstream или std::istringstream).
std::string json = R"({"value0": 42})";
std::istringstream iss(json);
{
cereal::JSONInputArchive archive(iss);
int value;
archive(value);
std::cout << value; // 42
}
3. cereal::BinaryOutputArchive / cereal::BinaryInputArchive
Что делает: Сериализация/десериализация в компактный бинарный формат. Быстрее JSON, но нечитаем.
Параметры: Аналогично JSON-архивам.
#include <cereal/archives/binary.hpp>
std::ostringstream oss;
{
cereal::BinaryOutputArchive archive(oss);
double pi = 3.14159;
archive(pi);
}
std::istringstream iss(oss.str());
{
cereal::BinaryInputArchive archive(iss);
double pi_restored;
archive(pi_restored);
std::cout << pi_restored; // 3.14159
}
4. cereal::XMLOutputArchive / cereal::XMLInputArchive
Что делает: Сериализация/десериализация в XML-формат. Полезно для совместимости с другими системами.
Параметры: Аналогично.
#include <cereal/archives/xml.hpp>
std::ostringstream oss;
{
cereal::XMLOutputArchive archive(oss);
std::string text = "Hello";
archive(text);
}
std::cout << oss.str(); // <?xml version="1.0"?><cereal><value0>Hello</value0></cereal>
5. CEREAL_NVP (Name-Value Pair)
Что делает: Присваивает имя переменной при сериализации. Без него cereal использует автоматические имена (value0, value1...).
Параметры: Принимает имя (строковый литерал) и переменную.
int x = 10;
archive(CEREAL_NVP(x)); // В JSON: {"x": 10}
6. cereal::make_nvp
Что делает: Аналог CEREAL_NVP, но может использоваться в рантайме (например, имя — переменная).
Параметры: Строка (имя) и значение.
std::string key = "myKey";
int value = 5;
archive(cereal::make_nvp(key, value));
7. cereal::SizeTag
Что делает: Явно указывает размер контейнера при бинарной сериализации. Полезно для оптимизации.
Параметры: Размер (обычно size_t).
std::vector<int> vec = {1, 2, 3};
archive(cereal::make_size_tag(static_cast<cereal::size_type>(vec.size())));
for (int v : vec) archive(v);
8. cereal::specialize
Что делает: Позволяет переопределить поведение сериализации для конкретного типа (например, для сторонних библиотек).
Параметры: Тип, режим (Specialization::member_serialize и т.д.).
struct Point {
int x, y;
};
namespace cereal {
template <class Archive>
void serialize(Archive& ar, Point& p) {
ar(p.x, p.y);
}
}
9. cereal::traits::is_output_serializable / is_input_serializable
Что делает: Проверяет во время компиляции, можно ли сериализовать тип. Используется для SFINAE.
Параметры: Тип и архив.
static_assert(cereal::traits::is_output_serializable<int, cereal::JSONOutputArchive>::value, "int must be serializable");
10. cereal::detail::OutputArchiveBase::setNextName
Что делает: Устанавливает имя для следующего элемента (низкоуровневый метод). Обычно не требуется.
Параметры: Строка.
archive.setNextName("customName");
archive(someValue);
Реальный практический пример использования
Представьте, что вы пишете игру и хотите сохранять состояние игрока (инвентарь, позицию, здоровье) в файл. Вот как это сделать с cereal:
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cereal/archives/json.hpp>
#include <cereal/types/vector.hpp>
#include <cereal/types/string.hpp>
struct Item {
std::string name;
int count;
template<class Archive>
void serialize(Archive& ar) {
ar(CEREAL_NVP(name), CEREAL_NVP(count));
}
};
struct Player {
std::string name;
int health;
float posX, posY;
std::vector<Item> inventory;
template<class Archive>
void serialize(Archive& ar) {
ar(CEREAL_NVP(name), CEREAL_NVP(health), CEREAL_NVP(posX), CEREAL_NVP(posY), CEREAL_NVP(inventory));
}
};
int main() {
Player player;
player.name = "Hero";
player.health = 100;
player.posX = 10.5f;
player.posY = 20.3f;
player.inventory = {{"Sword", 1}, {"Potion", 5}, {"Gold", 100}};
// Сохраняем
{
std::ofstream file("savegame.json");
cereal::JSONOutputArchive archive(file);
archive(CEREAL_NVP(player));
}
// Загружаем
Player loaded;
{
std::ifstream file("savegame.json");
cereal::JSONInputArchive archive(file);
archive(loaded);
}
std::cout << "Loaded player: " << loaded.name << " at position (" << loaded.posX << ", " << loaded.posY << ")" << std::endl;
std::cout << "Inventory: ";
for (const auto& item : loaded.inventory) {
std::cout << item.name << " x" << item.count << " ";
}
std::cout << std::endl;
return 0;
}
Этот код создаёт файл savegame.json, который можно редактировать вручную или передавать между сессиями игры.
Советы и типичные ошибки
- Ошибка
Также в библиотеке
Обработка Markdown в TypeScript: библиотеки, парсеры и практическое применение
OAuth клиент для Kotlin: библиотека Ktor OAuth для аутентификации в API
Elasticsearch клиент для Java: полное руководство по подключению и работе
Работа с S3 и облачными хранилищами в C++: библиотека aws-sdk-cpp