cereal для C++: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Что такое 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: Ручная установка (рекомендуется для обучения)

  1. Скачайте последнюю версию с GitHub (зелёная кнопка "Code" → "Download ZIP").
  2. Распакуйте архив.
  3. Скопируйте папку include/cereal в папку с вашим проектом.
  4. В коде подключайте: #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, который можно редактировать вручную или передавать между сессиями игры.

Советы и типичные ошибки

  • Ошибка

Рекомендаций