可行,但仅限于 trivially_copyable 的纯 pod 结构体(无虚函数、无指针、无 std::string 等非平凡成员);含动态成员或跨平台时必失败,须手写逐字段 serialize/deserialize 并统一字节序与对齐。

直接用 memcpy 序列化简单结构体可行吗?
仅当对象是 trivially_copyable 类型时才安全,比如纯 POD 结构体(无虚函数、无非静态引用、无自定义构造/析构/拷贝函数、所有成员可平凡复制)。一旦含 std::string、std::vector、指针或继承关系,memcpy 会把指针地址或内部堆地址写进二进制流,反序列化后必然崩溃或读出垃圾数据。
- 检查方式:
std::is_trivially_copyable_v<t></t>编译期断言 - 常见陷阱:
class A { std::string s; };看似简单,但s内部有指针,不能 memcpy - 若确认是 POD,可直接:
std::vector<char> buf(sizeof(T)); memcpy(buf.data(), &obj, sizeof(T));</char>
如何手动实现 serialize() 和 deserialize()?
核心原则:逐字段处理,对非 POD 成员调用其自身序列化逻辑,并注意字节序和对齐。C++ 没有反射,必须显式编写。
- 字符串要先写长度(如
uint32_t),再写字符数据;读时先读长度,再resize后read - 容器如
std::vector<int></int>同理:先写 size,再循环写每个int - 跨平台务必统一字节序:网络序(big-endian)更稳妥,用
htons/htonl或std::byteswap(C++23) - 示例片段:
void serialize(std::ostream& os) const { uint32_t len = static_cast<uint32_t>(name.length()); os.write(reinterpret_cast<const char>(&len), sizeof(len)); os.write(name.data(), len); }</const></uint32_t>
用 boost::serialization 有什么实际代价?
它能自动处理指针、继承、共享对象等复杂情况,但引入显著运行时开销和构建依赖,且二进制格式不兼容其他语言。
- 序列化文件不是紧凑二进制,含类型名、版本号、归档元信息,体积大、解析慢
- 需为每个类添加宏:
BOOST_SERIALIZATION_SPLIT_MEMBER()或serialize成员函数 - 反序列化时依赖相同编译器、相同 Boost 版本、相同类定义——哪怕加个私有成员都可能失败
- 若只需 C++ ↔ C++ 且追求性能,不如手写;若需快速支持复杂对象图且接受体积/速度损失,它省心
为什么推荐 flatbuffers 或 capn proto 而非自己造轮子?
它们生成的二进制可零拷贝读取、无需反序列化过程、schema 驱动、跨语言,比手写更可靠,比 Boost 更轻量。
-
flatbuffers:编译 schema 得到 C++ 头文件,GetRoot<mytable>(buf)</mytable>直接获得结构体指针,字段访问即内存偏移计算 -
capn proto:类似,但默认使用小端、支持 RPC,生成代码更冗长但语义更清晰 - 两者都强制你定义
.fbs或.capnpschema,杜绝“忘记序列化某个新字段”的问题 - 坑点:schema 变更需考虑向后兼容(如字段加
default、禁用重命名、用union替代删字段)
flatbuffers 这类工具不是偷懒,是把校验和布局逻辑交给经过千锤百炼的生成器。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











