背景
序列化
开发者在编写应用程序时通常需要将程序的一些数据存储在内存中,然后将其写入文件或传输到另一台计算机上以实现通信。
这个将数据转化成能被存储并传输的格式的过程被称为“序列化”
Cereal
Cereal 是一个 C++11 的序列化库,它是现代、轻量级、快速和灵活的,可以用来保存和加载几乎所有类型的数据。
Cereal 支持将自定义数据类型序列化成 JSON、XML、二进制,反之也可以实现反序列化。
Cereal
概述
Cereal 库提供了一个高效,类型安全,易用,可扩展的解决方案,可用于各种复杂的应用场景。
基本特性
-
类型安全:加载时类型不匹配会编译错误而非运行错误。 -
可扩展:支持自定义序列化函数适用于各类和复杂类型。 -
多格式支持:二进制、XML、JSON等格式可供选择。 -
无侵入性:你无需修改类或者函数就能对其进行序列化。 -
兼容性:易于管理版本迭代中数据结构的变化。
应用场景
数据持久化
数据持久化是将数据保存到硬盘上,后续加载使用的过程。例如,保存游戏状态和应用程序设置的需求。
网络通信
网络通信需要将数据序列化为可在网络上传输的格式,接收端进行反序列化以获取原始信息。
进程间通信
多进程间需要通过序列化数据传输,如管道、消息队列、共享内存等进程间通信机制。
数据库操作
许多情况下,数据被序列化并存储在数据库中,当需要读取时再进行反序列化操作。
Cereal 使用
下载与编译
Cereal GitHub 地址:https://github.com/USCiLab/cereal。
Cereal 是一个 head only 的库,无需编译。
基本使用
头文件引用
在项目设置中添加头文件引用:
序列化为二进制
把自定义对象序列化为二进制数据示例如下:
#include <iomanip>
#include <iostream>
#include <sstream>
#include <cereal/archives/binary.hpp>
#include <cereal/types/string.hpp>
#include <cereal/types/vector.hpp>
struct demo_struct { //自定义结构体
int id{};
std::string name;
std::vector<double> values;
template<class Archive>
void serialize(Archive& archive) // 序列化函数
{
archive(id, name, values);
}
};
int main() {
demo_struct data; // 自定义对象
data.id = 1;
data.name = "Example";
data.values = { 3.14, 2.718, 1.414 };
// 将结构体序列化为Binary字符串
std::ostringstream oss(std::ios::binary);
{
cereal::BinaryOutputArchive archive(oss);
archive(data);
}
// 输出序列化后的Binary字符串到控制台
std::string serializedData = oss.str();
for (char byte : serializedData) {
std::cout << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(static_cast<unsigned char>(byte)) << " ";
}
std::cout << std::endl;
// 从Binary字符串反序列化结构体
{
demo_struct loaded_data;
std::istringstream iss(oss.str());
cereal::BinaryInputArchive archive(iss);
archive(loaded_data);
// 显示反序列化后的数据
std::cout << "\nLoaded ID: " << loaded_data.id << std::endl;
std::cout << "Loaded Name: " << loaded_data.name << std::endl;
std::cout << "Loaded Values: ";
for (const auto& value : loaded_data.values) {
std::cout << value << " ";
}
std::cout << std::endl;
}
return 0;
}
运行结果如下:
序列化为 Xml
把自定义对象序列化为 Xml 数据示例如下:
#include <iostream>
#include <sstream>
#include <cereal/archives/xml.hpp>
#include <cereal/types/vector.hpp>
struct demo_struct { //自定义结构体
int id{};
std::string name;
std::vector<double> values;
template<class Archive>
void serialize(Archive& archive) // 序列化函数
{
archive(id, name, values);
}
};
int main() {
demo_struct data; // 自定义对象
data.id = 1;
data.name = "Example";
data.values = { 3.14, 2.718, 1.414 };
// 将结构体序列化为XML字符串
std::ostringstream oss;
{
cereal::XMLOutputArchive archive(oss);
archive(data);
}
// 输出序列化后的XML字符串到控制台
std::cout << "序列化为 XML:\n" << oss.str() << std::endl;
// 从XML字符串反序列化结构体
{
demo_struct loaded_data;
std::istringstream iss(oss.str());
cereal::XMLInputArchive archive(iss);
archive(loaded_data);
// 显示反序列化后的数据
std::cout << "\nLoaded ID: " << loaded_data.id << std::endl;
std::cout << "Loaded Name: " << loaded_data.name << std::endl;
std::cout << "Loaded Values: ";
for (const auto& value : loaded_data.values) {
std::cout << value << " ";
}
std::cout << std::endl;
}
return 0;
}
运行结果:
序列号为 Json
把自定义对象序列化为 Json 数据示例如下:
#include <iostream>
#include <sstream>
#include <cereal/archives/json.hpp>
#include <cereal/types/vector.hpp>
struct demo_struct { //自定义结构体
int id{};
std::string name;
std::vector<double> values;
template<class Archive>
void serialize(Archive& archive) // 序列化函数
{
archive(id, name, values);
}
};
int main() {
demo_struct data; // 自定义对象
data.id = 1;
data.name = "Example";
data.values = { 3.14, 2.718, 1.414 };
// 将结构体序列化为JSON字符串
std::ostringstream oss;
{
cereal::JSONOutputArchive archive(oss);
archive(data);
}
// 输出序列化后的JSON字符串到控制台
std::cout << "序列化为 JSON:\n" << oss.str() << std::endl;
// 从JSON字符串反序列化结构体
{
demo_struct loaded_data;
std::istringstream iss(oss.str());
cereal::JSONInputArchive archive(iss);
archive(loaded_data);
// 显示反序列化后的数据
std::cout << "\nLoaded ID: " << loaded_data.id << std::endl;
std::cout << "Loaded Name: " << loaded_data.name << std::endl;
std::cout << "Loaded Values: ";
for (const auto& value : loaded_data.values) {
std::cout << value << " ";
}
std::cout << std::endl;
}
return 0;
}
总结
任何涉及将内存中的数据结构转换为可以存储或传输的格式的场景,都可能需要使用序列化。
在简单的性能测试中,Cereal 通常比 Boost 的序列化库速度更快,而且产生的二进制形式占用更少的空间,尤其是针对更小的对象。

