C++如何使用Cereal库进行对象序列化_C++序列化库Cereal使用指南

Cereal 是一个轻量级头文件-only 的 C++ 序列化库,支持二进制、JSON 和 XML 格式。1. 通过包含 cereal 头文件并定义 serialize 函数实现类的序列化;2. 使用 JSONOutputArchive/JSONInputArchive 进行 JSON 读写;3. 利用 BinaryOutputArchive/BinaryInputArchive 支持高效二进制序列化;4. 原生支持 STL 容器如 vector、map;5. 可通过非成员函数在 cereal 命名空间中实现非侵入式序列化;6. 注意使用 CEREAL_NVP 命名字段、避免裸指针、确保默认构造函数可用。

在C++中,对象序列化是将数据结构或对象状态转换为可存储或传输格式的过程。Cereal 是一个轻量级、头文件-only 的 C++ 序列化库,支持二进制、JSON 和 XML 格式,使用简单且无需依赖外部编译器。下面介绍如何使用 Cereal 实现对象的序列化与反序列化。

安装与配置 Cereal

Cereal 是纯头文件库,无需编译,直接包含即可使用。

  • 从 GitHub 下载:https://github.com/USCiLab/cereal
  • 将 cereal 源码目录(include/cereal)添加到项目包含路径
  • 在代码中通过 #include json.hpp> 等引入所需模块

基本类的序列化实现

要使自定义类支持序列化,需在类内或类外定义 serialize 函数。

例如,定义一个 Person 类:

person.hpp

#include 
#include 

class Person {
private:
    std::string name;
    int age;

    // 允许 cereal 访问私有成员
    friend class cereal::access;

    template
    void serialize(Archive& ar) {
        ar( CEREAL_NVP(name), CEREAL_NVP(age) );
    }

public:
    Person() = default;
    Person(std::string n, int a) : name(std::move(n)), age(a) {}
};

通过 cereal::access 友元声明,让 Cereal 能访问私有成员。使用 CEREAL_NVP 可以自动命名字段,在 JSON 或 XML 中更清晰。

序列化到 JSON 文件

将对象保存为 JSON 格式便于阅读和调试。

示例:序列化 Person 对象到文件

save.cpp

#include "person.hpp"
#include 
#include 

int main() {
    Person p("Alice", 30);

    std::ofstream os("person.json");
    cereal::JSONOutputArchive archive(os);
    archive(CEREAL_NVP(p));

    return 0;
}

生成的 person.json 内容如下:

{
    "p": {
        "name": "Alice",
        "age": 30
    }
}

从 JSON 文件反序列化

读取并恢复对象状态也很简单。

load.cpp

#include "person.hpp"
#include 
#include 

int main() {
    Person p;

    std::ifstream is("person.json");
    cereal::JSONInputArchive archive(is);
    archive(p);  // 注意:这里不需要 CEREAL_NVP

    return 0;
}

执行后,p 对象将恢复为保存时的状态。

支持二进制序列化

二进制格式更紧凑,适合高性能场景。

保存为二进制:
std::ofstream os("data.bin", std::ios::binary);
cereal::BinaryOutputArchive archive(os);
archive(p);
从二进制读取:
std::ifstream is("data.bin", std::ios::binary);
cereal::BinaryInputArchive archive(is);
archive(p);

序列化 STL 容器

Cereal 原生支持大多数 STL 容器,如 vector、map、unordered_set 等。

std::vector people = {{"Alice", 30}, {"Bob", 25}};

// 序列化整个容器
archive(CEREAL_NVP(people));

可以直接序列化包含容器的类,无需额外处理。

非侵入式序列化(不修改原类)

如果无法修改类定义,可以使用非成员函数方式。

namespace cereal {
template
void serialize(Archive& ar, Person& p) {
    ar( CEREAL_NVP(p.name), CEREAL_NVP(p.age) );
}
}

将 serialize 定义在 cereal 命名空间中,效果等同于类内实现。

注意事项与技巧

  • 确保构造函数为 public,即使为空(default 即可)
  • 序列化类型必须支持对应存档格式(如 XML 不支持指针)
  • 使用版本控制可应对类结构变更(通过 versioning 支持)
  • 避免序列化裸指针,推荐使用智能指针或值对象
基本上就这些。Cereal 使用现代 C++ 特性(模板、SFINAE)实现了简洁高效的序列化机制,适合大多数项目需求。只要正确声明 serialize 方法,就能轻松实现对象持久化。