C++含自定义类型成员的Mango类序列化反序列化最优实现问询
问题描述
需要实现C++类Mango的序列化与反序列化函数,该类包含10个类似MangoType的复杂自定义类型成员。当前已定义框架函数,但不确定:
serialize的返回类型(比如std::vector<uint8_t>还是直接写入内存)deserialize的参数类型
希望获得兼顾速度、内存占用、可移植性的最优实现方案。
场景说明
序列化后的数据仅用于本地存储复用,无需网络传输,目的是避免每次重新计算加载Mango数据的耗时。
额外需求
不想使用需要链接的序列化库,询问能否以仅头文件形式使用Boost Serialization。
相关代码框架
? serialize(Mango &Man) /// What should be return ? { } Mango deserialize( ? ) /// What should be function parameter ? { }
类定义
Mango类
class Mango { public: const MangoType &getMangoType() const { return typeMan; } MangoType &getMangoType() { return typeMan; } private: // 实际包含10个不同类型的成员,此处仅示例一个 MangoType typeMan; };
自定义数据类型
// MangoType类 class MangoType { public: std::vector<FuntionMango> &getContent() noexcept { return Content; } private: std::vector<FuntionMango> Content; }; // FuntionMango类 class FuntionMango { public: const std::vector<ValType> &getParamTypes() const noexcept { return ParamTypes; } std::vector<ValType> &getParamTypes() noexcept { return ParamTypes; } const std::vector<ValType> &getReturnTypes() const noexcept { return ReturnTypes; } std::vector<ValType> &getReturnTypes() noexcept { return ReturnTypes; } private: std::vector<ValType> ParamTypes; std::vector<ValType> ReturnTypes; }; // ValType枚举类 enum class ValType : uint8_t { #define UseValType #define Line(NAME, VALUE, STRING) NAME = VALUE #undef Line #undef UseValType };
解决方案
一、序列化/反序列化的类型选择
1. serialize返回类型:std::vector<uint8_t>
- 速度:内存中连续存储,写入文件时可一次性IO,减少磁盘操作次数;
- 内存占用:仅存储实际序列化数据,无额外冗余,可先在内存构建完整数据再落地,避免多次文件IO开销;
- 可移植性:标准容器跨平台兼容,手动处理多字节类型的字节序即可保证不同系统间的兼容性。
2. deserialize参数类型:const std::vector<uint8_t>& 或 std::span<const uint8_t>(C++20+)
const std::vector<uint8_t>&:兼容性最好,支持所有C++版本;std::span<const uint8_t>:更轻量,无需拷贝整个缓冲区,适合C++20及以上环境,内存占用更低。
二、Boost Serialization仅头文件使用方式
完全可以仅用头文件形式使用Boost Serialization:只需在项目中定义宏BOOST_SERIALIZATION_DYN_LINK=0(或直接不定义BOOST_SERIALIZATION_DYN_LINK),包含所需头文件即可,无需链接Boost序列化库。
三、具体实现示例
1. 手动序列化(无外部依赖)
适合轻量场景,速度和内存控制最优,但需手动处理所有类型:
#include <vector> #include <cstdint> #include <algorithm> // 辅助:写入POD类型到缓冲区 template<typename T> void write_pod(std::vector<uint8_t>& buf, const T& val) { static_assert(std::is_trivial_v<T> && std::is_standard_layout_v<T>, "T must be POD"); const uint8_t* ptr = reinterpret_cast<const uint8_t*>(&val); buf.insert(buf.end(), ptr, ptr + sizeof(T)); } // 辅助:从缓冲区读取POD类型 template<typename T> T read_pod(const uint8_t*& ptr) { static_assert(std::is_trivial_v<T> && std::is_standard_layout_v<T>, "T must be POD"); T val = *reinterpret_cast<const T*>(ptr); ptr += sizeof(T); return val; } std::vector<uint8_t> serialize(const Mango& man) { std::vector<uint8_t> buf; // 序列化MangoType const auto& type_man = man.getMangoType(); const auto& content = type_man.getContent(); uint32_t content_size = static_cast<uint32_t>(content.size()); write_pod(buf, content_size); for (const auto& func : content) { // 序列化ParamTypes uint32_t param_size = static_cast<uint32_t>(func.getParamTypes().size()); write_pod(buf, param_size); for (ValType vt : func.getParamTypes()) { write_pod(buf, static_cast<uint8_t>(vt)); } // 序列化ReturnTypes uint32_t return_size = static_cast<uint32_t>(func.getReturnTypes().size()); write_pod(buf, return_size); for (ValType vt : func.getReturnTypes()) { write_pod(buf, static_cast<uint8_t>(vt)); } } // 添加其他9个Mango成员的序列化逻辑... return buf; } Mango deserialize(const std::vector<uint8_t>& buf) { Mango man; const uint8_t* ptr = buf.data(); const uint8_t* end = ptr + buf.size(); // 反序列化MangoType auto& type_man = man.getMangoType(); auto& content = type_man.getContent(); uint32_t content_size = read_pod<uint32_t>(ptr); content.reserve(content_size); for (uint32_t i = 0; i < content_size; ++i) { FuntionMango func; // 反序列化ParamTypes uint32_t param_size = read_pod<uint32_t>(ptr); auto& params = func.getParamTypes(); params.reserve(param_size); for (uint32_t j = 0; j < param_size; ++j) { uint8_t vt_val = read_pod<uint8_t>(ptr); params.emplace_back(static_cast<ValType>(vt_val)); } // 反序列化ReturnTypes uint32_t return_size = read_pod<uint32_t>(ptr); auto& returns = func.getReturnTypes(); returns.reserve(return_size); for (uint32_t j = 0; j < return_size; ++j) { uint8_t vt_val = read_pod<uint8_t>(ptr); returns.emplace_back(static_cast<ValType>(vt_val)); } content.push_back(std::move(func)); } // 添加其他9个Mango成员的反序列化逻辑... return man; }
2. Boost Serialization仅头文件实现
代码简洁,无需手动处理复杂容器,维护成本低:
#define BOOST_SERIALIZATION_DYN_LINK 0 // 禁用动态链接,仅用头文件 #include <boost/serialization/vector.hpp> #include <boost/serialization/access.hpp> #include <boost/archive/binary_oarchive.hpp> #include <boost/archive/binary_iarchive.hpp> #include <vector> #include <sstream> // 为MangoType添加序列化支持 class MangoType { public: std::vector<FuntionMango> &getContent() noexcept { return Content; } const std::vector<FuntionMango> &getContent() const noexcept { return Content; } private: std::vector<FuntionMango> Content; friend class boost::serialization::access; template<typename Archive> void serialize(Archive& ar, const unsigned int version) { ar & Content; } }; // 为FuntionMango添加序列化支持 class FuntionMango { public: const std::vector<ValType> &getParamTypes() const noexcept { return ParamTypes; } std::vector<ValType> &getParamTypes() noexcept { return ParamTypes; } const std::vector<ValType> &getReturnTypes() const noexcept { return ReturnTypes; } std::vector<ValType> &getReturnTypes() noexcept { return ReturnTypes; } private: std::vector<ValType> ParamTypes; std::vector<ValType> ReturnTypes; friend class boost::serialization::access; template<typename Archive> void serialize(Archive& ar, const unsigned int version) { ar & ParamTypes & ReturnTypes; } }; // 为Mango添加序列化支持 class Mango { public: const MangoType &getMangoType() const { return typeMan; } MangoType &getMangoType() { return typeMan; } private: MangoType typeMan; // 其他9个成员... friend class boost::serialization::access; template<typename Archive> void serialize(Archive& ar, const unsigned int version) { ar & typeMan; // 序列化其他9个成员... } }; // 序列化函数 std::vector<uint8_t> serialize(const Mango& man) { std::ostringstream oss; boost::archive::binary_oarchive oa(oss); oa << man; const std::string& str = oss.str(); return std::vector<uint8_t>(str.begin(), str.end()); } // 反序列化函数 Mango deserialize(const std::vector<uint8_t>& buf) { std::string str(buf.begin(), buf.end()); std::istringstream iss(str); boost::archive::binary_iarchive ia(iss); Mango man; ia >> man; return man; }
方案对比
- 手动序列化:无外部依赖,速度最快,内存占用最低,但需手动处理所有类型,维护成本高;
- Boost仅头文件:代码简洁,无需手动处理复杂容器,维护成本低,性能略逊于手动实现,但完全满足本地存储需求。
内容的提问来源于stack exchange,提问作者James_sheford
相关产品推荐
相关产品推荐

