cereal:支持C++11的开源序列化库

news2024/11/17 5:53:27

cereal:支持C++11的开源序列化库

文章目录

  • 一:引言
  • 二、cereal简介
  • 三、cereal的下载和使用

一:引言

序列化 (Serialization)

程序员在编写应用程序的时候往往需要将程序的某些数据存储在内存中,然后将其写入某个文件或是将它传输到网络中的另一台计算机上以实现通讯。这个将程序数据转化成能被存储并传输的格式的过程被称为“序列化”(Serialization),而它的逆过程则可被称为“反序列化” (Deserialization)。

值得推荐的开源C/C++框架和库:https://www.cnblogs.com/lidabo/p/5514155.html

二、cereal简介

cereal是一个开源的(BSD License)、轻量级的、支持C++11特性的、仅仅包含头文件实现的、跨平台的C++序列化库。它可以将任意的数据类型序列化成不同的表现形式,比如二进制、XML格式或JSON。cereal的设计目标是快速、轻量级、易扩展——它没有外部的依赖关系,而且可以很容易的和其他代码封装在一块或者单独使用。

cereal支持标准库的几乎每一个类型的序列化。cereal也完全支持继承和多态。由于cereal被设计为一个精简、快速的库,它不像其他序列化库(比如Boost)在同一层次上会进行对象跟踪,这也导致了它不支持原始指针(raw pointer)和引用,但是智能指针(比如std::shared_ptr和std::unique_ptr)是没有问题的。

cereal适用于基于C++11标准的各种编译器

cereal使用了一些C++11的新特性,因此需要一个兼容性更好的的C++编译器才能正常工作。已被验证可用的编译器有g++4.7.3、clang++3.3、MSVC2013,或者更新版本。

它也可能可以在老版本编译器上工作,但并不保证完全支持。当使用g++或clang++编译器时,cereal同时需要libstdc++和libc++库。

cereal:更快速,更好的压缩
在简单的性能测试中,cereal通常比Boost的序列化库速度更快,而且产生的二进制形式占用更少的空间,尤其是针对更小的对象。cereal使用了C++中的速度最快的XML和JSON解析器和包装器。

cpp-serializers 这个项目中,作者对比了目前常见的序列化库:
在这里插入图片描述

可视化的模型对比
在这里插入图片描述

平均时间
在这里插入图片描述

可以看到,cereal在大小和时间上都有不错的表现(其实yas的速度好像更快,回头评测一下。。)

cereal是易于使用的

在代码增加cereal序列化功能可以简化为包含一个头文件,写一个序列化函数。无论是从概念上还是代码层次上,cereal的功能都是自文档化的。
如果你使用错误,cereal尽可能的在编译期触发静态断言。

对于Boost使用者来说,cereal提供了相似的语法,如果你使用过Boost的序列化库,你会发现cereal的语法看起来很熟悉。

如果你是从Boost转向使用cereal,一定要阅读这个过渡指南:http://uscilab.github.io/cereal/transition_from_boost.html

三、cereal的下载和使用

cereal的官方下载地址为:http://uscilab.github.io/cereal/index.html

编译源码过程很简单,在此不详述(注意源码解压在全英文路径下进行编译,不然出现编译失败的错误)。

使用cmake工具对源码进行编译和安装,选择对应版本的编译器和x86/x64选项,最终释放出一系列头文件到安装路径:


在这里插入图片描述

将cereal文件夹拷贝到指定位置,并设置系统环境变量为头文件所在路径,如:“D:\3rdLib\cereal\include”。

接下来就可以使用cereal库了~

我这里给他封装成了两个头文件:ConfigFile.h和ConfigComm.h

ConfigFile.h:

#ifndef _ConfigFile_Head_File_
#define _ConfigFile_Head_File_


#include <cereal/archives/json.hpp>
#include <fstream>
#include "ConfigComm.h"

template<typename DataType>
class ConfigFile
{
public:
	int SetConfigFile(std::string configFile)
	{
		_configFile = configFile;

		std::ifstream f(_configFile);
		if (f.good() == true)
		{
			_fileExist = true;
			return 1;
		}

		_errMsg = "配置文件 \"" + _configFile + "\" 不存在";
		return -1;
	}

	int Load()
	{
		if (_fileExist == false)
		{
			_errMsg = "配置文件 \"" + _configFile + "\" 不存在";
			return -1;
		}

		try
		{
			std::ifstream is(_configFile);
			cereal::JSONInputArchive ar(is);
			ar(_data);
		}
		catch (CerealError err)
		{
			_errMsg = "配置文件 \"" + _configFile + "\" " + err.errMsg;
			return -1;
		}
		catch (...)
		{
			_errMsg = "配置文件 \"" + _configFile + "\" 存在错误";
			return -1;
		}

		return 1;
	}

	int Save()
	{
		if (_configFile.empty() == true)
		{
			_errMsg = "配置文件路径为空";
			return -1;
		}

		try
		{
			std::ofstream os(_configFile);
			cereal::JSONOutputArchive ar(os);
			ar(cereal::make_nvp("配置信息", _data));
		}
		catch (...)
		{
			_errMsg = "配置文件 \"" + _configFile + "\" 保存失败";
			return -1;
		}

		return 1;
	}

	int Load(std::string filename)
	{
		if (SetConfigFile(filename) > 0)
			return Load();

		return -1;
	}

	int Save(std::string filename)
	{
		_configFile = filename;
		return Save();
	}

	DataType& Data()
	{
		return _data;
	}

private:
	bool _fileExist = false;
	std::string _configFile;

	DataType _data;

public:
	std::string GetLastErrorMsg() { return _errMsg; }

protected:
	std::string _errMsg;
};

struct FileListConfig
{
	std::vector<std::string> lst;

	template<class Archive>
	void serialize(Archive& archive)
	{
		CustomCereal(archive, "配置文件列表", lst);
	}
};

template<typename DataType>
class ConfigFileList
{
public:
	int SetListConfigFile(std::string listConfigFile)
	{
		_listConfigFile = listConfigFile;

		ConfigFile<FileListConfig> flc;
		if (flc.SetConfigFile(_listConfigFile) > 0)
		{
			_fileExist = true;

			if (flc.Load() > 0)
			{
				_cfList.clear();

				for (std::string filename : flc.Data().lst)
				{
					ConfigFile<DataType> configFile;
					if (configFile.SetConfigFile(filename) > 0)
					{
						_cfList.push_back(configFile);
					}
					else
					{
						_errMsg = configFile.GetLastErrorMsg();
						return -1;
					}
				}
			}
			else
			{
				_errMsg = flc.GetLastErrorMsg();
				return -1;
			}

			return 1;
		}

		_errMsg = "列表配置文件 \"" + _listConfigFile + "\" 不存在";
		return -1;
	}

	int Load()
	{
		if (_fileExist == false)
		{
			_errMsg = "列表配置文件 \"" + _listConfigFile + "\" 不存在";
			return -1;
		}

		for (ConfigFile<DataType>& configFile : _cfList)
		{
			if (configFile.Load() < 0)
			{
				_errMsg = configFile.GetLastErrorMsg();
				return -1;
			}
		}

		if (_cfList.size() == 0)
		{
			_errMsg = "列表配置文件 \"" + _listConfigFile + "\" 列表数据为空";
			return  -1;
		}

		return 1;
	}

	int Save()
	{
		if (_cfList.size() == 0)
		{
			_errMsg = "列表配置文件 \"" + _listConfigFile + "\" 保存数据为空";
			return -1;
		}

		for (ConfigFile<DataType>& configFile : _cfList)
		{
			if (configFile.Save() < 0)
			{
				_errMsg = configFile.GetLastErrorMsg();
				return -1;
			}
		}

		return 1;
	}

	int Load(std::string listConfigFile)
	{
		if (SetListConfigFile(listConfigFile) > 0)
			return Load();

		return -1;
	}

	int Save(std::string listConfigFile)
	{
		_listConfigFile = listConfigFile;	

		ConfigFile<FileListConfig> flc;
		if (flc.SetConfigFile(_listConfigFile) > 0)
		{
			if (flc.Load() > 0)
			{
				for (std::string filename : flc.Data().lst)
				{
					ConfigFile<DataType> configFile;
					if (configFile.Save(filename) < 0)
					{
						_errMsg = configFile.GetLastErrorMsg();
						return -1;
					}
				}
			}
			else
			{
				_errMsg = flc.GetLastErrorMsg();
				return -1;
			}

			return 1;
		}
		
		_errMsg = flc.GetLastErrorMsg();
		return -1;
	}

	int Size()
	{
		return _cfList.size();
	}

	DataType& operator[](int index)
	{
		return _cfList[index].Data();
	}

private:
	bool _fileExist = false;
	std::string _listConfigFile;

	std::vector<ConfigFile<DataType>> _cfList;

public:
	std::string GetLastErrorMsg() { return _errMsg; }

protected:
	std::string _errMsg;
};

#endif//_ConfigFile_Head_File_
 

ConfigComm.h

#ifndef _ConfigComm_Head_File_
#define _ConfigComm_Head_File_

#include <cereal/types/base_class.hpp>
#include <cereal/types/string.hpp>
#include <cereal/types/vector.hpp>
#include <cereal/types/array.hpp>
#include <cereal/types/map.hpp>

struct CerealError
{
	CerealError(std::string err)
	{
		errMsg = err;
	}

	std::string errMsg = "";
};

template<class Archive, typename valueType>
void CustomCereal(Archive& archive, std::string itemName, valueType& value, bool canIgnore = false)
{
	try
	{
		archive(cereal::make_nvp(itemName, value));
	}
	catch (...)
	{
		if (canIgnore == false)
		{
			std::string msg = itemName + " 错误";
			throw CerealError(msg);
		}
	}
}

template<typename Type>
static void CerealOutputFile(std::string fileName, std::string rootName, Type data)
{
	try
	{
		std::ofstream os(fileName);
		cereal::JSONOutputArchive ar(os);
		ar(cereal::make_nvp(rootName, data));
	}
	catch (...)
	{
	}
}

template<typename Type>
static Type CerealInputFile(std::string fileName, std::string rootName)
{
	Type data;
	try
	{
		std::ifstream is(fileName);
		cereal::JSONInputArchive ar(is);

		ar(cereal::make_nvp(rootName, data));
	}
	catch (...)
	{
	}

	return data;
}


template<typename Type>
static std::string CerealOutputString(Type data)
{
	std::ostringstream os;
	try
	{
		cereal::JSONOutputArchive ar(os);
		ar(CEREAL_NVP(data));
	}
	catch (...)
	{
		return "";
	}

	std::string s = os.str();
	return 	s;
}

template<typename Type>
static bool CerealInputString(std::string str, Type &data)
{
	try
	{
		std::istringstream is(str);
		cereal::JSONInputArchive ar(is);
		ar(CEREAL_NVP(data));
		return 	true;
	}
	catch (std::exception ex)
	{
		return 	false;
	}
}

class IConfigBase
{
public:
	virtual ~IConfigBase() = default;

	virtual int LoadConfig(std::string configFile) = 0;
	virtual int UpdateConfig() = 0;
	virtual int SaveConfig() = 0;

	virtual void* GetConfigData() = 0;
	virtual void* GetConfigPanel(int panelMode = 0) = 0;
};

#endif//_ConfigComm_Head_File_

创建实例Test测试:

// CerealTest.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include "ConfigFile.h"

struct NetConfig
{
	bool bWireEnable = false;
	int telePort = 12345;
	int cmdPort = 12345;

	template<class Archive>
	void serialize(Archive& archive)
	{
		CustomCereal(archive, "是否为无线网络", bWireEnable);
		CustomCereal(archive, "遥测端口", telePort);
		CustomCereal(archive, "命令端口", cmdPort);
	}
};

int main()
{
	ConfigFile<LogConfig> NetConfig;

	bool t1 = NetConfig.Load("LogConfig.json");
	bool t2 = NetConfig.Save();
	int  x = NetConfig.Data().cmdPort;

	std::cout << t1 << t2 << x;  
}

具体实例和库代码可在此下载:https://download.csdn.net/download/cao_jie_xin/88380290

参考:https://zhuanlan.zhihu.com/p/391610360
https://blog.csdn.net/qq_21950929/article/details/105745509

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1065662.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

认识计算机主板

目录 定义主要部件简单图示 主要功能 定义 计算机主板&#xff08;Motherboard&#xff09;是计算机系统中的核心组件之一&#xff0c;也被称为系统板、主板或母板。它是一个电子电路板&#xff0c;用于连接和支持计算机的各种硬件组件&#xff0c;包括中央处理器&#xff08;…

零售业:别让数据安全成为业务的绊脚石!(附文件下载)

零售业上榜&#xff01; 截至2023年8月31日&#xff0c;南都大数据研究院通过各地行政执法公示平台、媒体报道等公开渠道&#xff0c;收集到146起依据《数据安全法》作出行政处罚决定的案例。梳理发现&#xff0c;零售业以10.27%的占比位居行业第三&#xff0c;成为数据安全行…

尚硅谷Nginx教程由浅入深--笔记

尚硅谷Nginx教程由浅入深--笔记 Nginx简介Nginx相关概念反向代理负载均衡动静分离 Nginx安装Nginx命令Nginx配置Nginx配置实例反向代理1反向代理2负载均衡动静分离 Nginx简介 Nginx是一个高性能的HTTP和反向代理服务器&#xff0c;特点是内存占用少&#xff0c;并发能力强。 …

高铁站高速稳定用网秘籍,赶紧收藏

中秋国庆黄金周将至&#xff0c;销售旺季即将来临。车来车往、人潮涌动&#xff0c;稳定可靠的网络连接&#xff0c;成为了各大小商户抢占市场、掌握流量密码的关键。 在湖南省郴州市&#xff0c;某食品连锁商店负责人正在为店铺网络问题发愁。该连锁店部分销售网点位于繁忙的高…

Pikachu靶场——暴力破解

文章目录 1. 暴力破解1.1 基于表单的暴力破解1.2 验证码绕过(on server)1.3 验证码绕过(on client)1.4 token防爆破?1.5 漏洞防御 1. 暴力破解 暴力破解漏洞是指攻击者通过尝试各种组合的用户名和密码&#xff0c;以暴力方式进入系统或应用程序的方法。它利用了系统或应用程序…

睿趣科技:新手无货源怎么开抖音小店

抖音小店的开设对于许多商家来说是一个有吸引力的选择&#xff0c;尤其是对于那些喜欢短视频和社交媒体的年轻人。然而&#xff0c;对于没有货源的新手来说&#xff0c;这可能是一个令人头疼的问题。这篇文章将为你提供一些解决方案。 首先&#xff0c;你可以考虑从批发市场购买…

掌握SKILL语言:数字IC设计师必备的技能之一

去年在各个平台更新了一篇《数字IC必学之《Skill入门教程》建议收藏&#xff01;》&#xff0c;阅读量在每个平台都很客观&#xff0c;且这半年以来&#xff0c;不断有粉丝留言想要获取这份资料。看来大家对于SKILL的需求是很大的&#xff0c;想要掌握SKILL语言&#xff1a;数字…

95、Spring Data Redis 之使用RedisTemplate 实现自定义查询 及 Spring Data Redis 的样本查询

Spring Data Redis 之使用RedisTemplate 实现自定义查询 Book实体类 原本的接口&#xff0c;再继承我们自定义的接口 自定义查询接口----CustomBookDao 实现类&#xff1a;CustomBookDaoImpl 1、自定义添加hash对象的方法 2、自定义查询价格高于某个点的Book对象 测试&a…

微信小程序wxs标签 在wxml文件中编写JavaScript逻辑

PC端开发 可以在界面中编写JavaScript脚本 vue/react这些框架更是形成了一种常态 因为模板引擎和jsx语法本身就都是在js中的 我们小程序中其实也有类似的奇妙写法 不过先声明 这东西不是很强大 我们可以先写一个案例代码 wxml代码参考 <view><wxs module"wordSt…

如何与瑞诺司Rhenus 建立EDI连接?

Rhenus Automotive 是德国百年家族企业Rethmann Group的子公司&#xff0c;提供从零部件的有序供应、即装即用模块的组装&#xff0c;一直到整车的组装。主要在全球范围内为劳斯莱斯&#xff0c;宝马&#xff0c;奔驰&#xff0c;奥迪等汽车企业提供智能制造解决方案。 项目挑战…

阿拉伯文排版是如何实现的

背景&#xff1a; 今天开工了&#xff0c;无意间看到多语言的页面&#xff0c;毕竟我们网站也是有多语言的 但是并没有阿拉伯语。但是我很好奇&#xff0c;分析阿拉伯语言的css并没有发现什么猫腻&#xff01; 到底是怎么实现的呢&#xff1f; 解&#xff1a; html dir 属性 …

聊聊MySQL的聚簇索引和非聚簇索引

文章目录 1. 索引的分类1. 存储结构维度2. 功能维度3. 列数维度4. 存储方式维度5. 更新方式维度 2. 聚簇索引2.1 什么是聚簇索引2.2 聚簇索引的工作原理 3. 非聚簇索引&#xff08;MySQL官方文档称为Secondary Indexes&#xff09;3.1 什么是非聚簇索引3.2 非聚簇索引的工作原理…

win7怎么录屏视频?小白也能轻松学会

“win7怎么录屏视频呀&#xff1f;在学校机房上课&#xff0c;电脑都是win7系统的&#xff0c;每次需要录屏的时候都找不到方法&#xff0c;问了老师也解决不了&#xff0c;有人知道win7怎么录屏吗&#xff1f;” Windows 7系统已经逐渐淡出了主流操作系统的行列&#xff0c;但…

JVM上篇之虚拟机与java虚拟机介绍

目录 虚拟机 java虚拟机 简介 特点 作用 位置 整体结构 类装载子系统 运行时数据区 java执行引擎 Java代码执行流程 jvm架构模型 基于栈式架构 基于寄存器架构 总结 jvm的生命周期 1.启动 2.执行 3.退出 JVM的发展历程 虚拟机 所谓虚拟机&#xff0c;指的…

要体验 AI 编程助手吗?

能不能用 AI 编程辅助写代码&#xff1f; 亚马逊云科技开发者社区为开发者们提供全球的开发技术资源。这里有技术文档、开发案例、技术专栏、培训视频、活动与竞赛等。帮助中国开发者对接世界最前沿技术&#xff0c;观点&#xff0c;和项目&#xff0c;并将中国优秀开发者或技术…

强化学习实践(二)Gym(安装、环境搭建、运行倒立摆(代码可运行))

1.准备工作 优先选用conda&#xff0c;conda不仅可以安装python&#xff0c;也是环境管理的工具&#xff0c;我们可以通过conda创建python环境&#xff0c;每个环境之间是相互独立&#xff0c;这样不同的环境可以使用不同版本的python&#xff0c;不同版本的开发包&#xff0c;…

UEditorPlus v3.5.0 支持音频组件,字体图标请求合并,服务器配置优化

UEditor是由百度开发的所见即所得的开源富文本编辑器&#xff0c;基于MIT开源协议&#xff0c;该富文本编辑器帮助不少网站开发者解决富文本编辑器的难点。 UEditorPlus 是有 ModStart 团队基于 UEditor 二次开发的富文本编辑器&#xff0c;主要做了样式的定制&#xff0c;更符…

栈溢出至getshell分析及利用

公众号&#xff1a;掌控安全EDU 分享更多技术文章&#xff0c;欢迎关注一起探讨学习 Ret2text&#xff08;源程序中存在system及/bin/sh&#xff09; 控制程序执行程序本身已有的的代码(.text)。栈溢出&#xff0c;存在system()函数以及”/bin/sh”字符串。通过溢出将返回地址…

LeetCode算法心得——有序三元组中的最大值 II (简单的动规思想)

大家好&#xff0c;我是晴天学长&#xff0c;枚举&#xff0b;简单的动态规划思想&#xff0c;需要的小伙伴可以关注支持一下哦&#xff01;后续会继续更新的。 1) .有序三元组中的最大值 II 有序三元组中的最大值 II 给你一个下标从 0 开始的整数数组 nums 。 请你从所有满足 …

STM32F4X UCOSIII 互斥量

STM32F4X UCOSIII 互斥量 互斥量的概念互斥量的工作机制洗手间问题互斥量优先级继承没有优先级继承优先级继承 UCOSIII互斥量API互斥量创建函数互斥量删除函数互斥量申请函数互斥量释放函数 UCOSIII 互斥量例程 互斥量的概念 UCOSIII中的互斥量是一种特殊的信号量&#xff0c;…