二进制序列化必须用 write() 而非

std::ofstream 写二进制时没调用 write() 会丢数据
直接用 operator 输出对象,本质是格式化文本输出,不仅不保存原始内存布局,还会跳过私有成员、触发隐式转换、丢失对齐信息。真正做二进制序列化必须绕过流操作符,用 <code>write() 手动写入字节块。
- 仅当类是 trivially copyable(如纯 POD 类型)时,才能安全地用
reinterpret_cast<char>(&obj)</char>+sizeof(obj)配合write() - 含指针、虚函数、
std::string、std::vector的类,不能直接 memcpy —— 这些字段存的是运行时地址或堆上指针,序列化后反序列化会解引用非法内存 - 写文件前务必检查
is_open()和good(),否则静默失败;写完要调close()或确认flush()已执行
用 boost::serialization 却连不上 archive 库
Boost.Serialization 不是头文件-only 库,#include <boost></boost> 只是声明,链接时必须显式加入 -lboost_serialization(Linux/macOS)或对应 .lib(Windows)。漏掉这步,编译能过,但链接报 undefined reference to `boost::archive::binary_oarchive_impl::...'。
- 确保安装的是完整 Boost(非仅头文件版),且版本 ≥ 1.56(旧版 binary archive 有 ABI 兼容问题)
- 自定义
serialize()函数必须声明在public区,且接受Archive&和const unsigned int两个参数 - 若类含模板成员或继承关系,需额外用
BOOST_CLASS_EXPORT导出类型,否则反序列化时无法识别
自己写 save()/load() 但跨平台读写失败
不同系统默认字节序(endianness)、结构体填充(padding)、int/long 大小都可能不同。比如 x86_64 Linux 下 long 是 8 字节,Windows MSVC 下是 4 字节 —— 直接写 sizeof(long) 会导致读取错位。
- 固定宽度类型优先:用
int32_t、uint64_t替代int、unsigned long - 结构体加
#pragma pack(1)或[[gnu::packed]]消除填充,但注意性能代价(非对齐访问在某些 CPU 上慢甚至崩溃) - 手动处理字节序:存前用
htons()/htonl(),读后用ntohs()/ntohl(),别依赖本地endian宏做条件编译
反序列化时 std::vector 数据全为零或越界
因为只写了 vector 的 size(比如 v.size()),却没写实际元素内容。或者写了 size 后,用 resize() 分配空间,再逐个 read(),但忘了 resize() 不保证内存连续 —— 实际上 std::vector::data() 才是合法的读写起点。
立即学习“C++免费学习笔记(深入)”;
- 正确做法:先读 size →
v.resize(n)→ 用v.data()获取首地址 →read(reinterpret_cast<char>(v.data()), n * sizeof(T))</char> - 若 vector 元素是非 trivial 类型(如含 string 的 struct),不能整块读,得循环单个序列化
- 读之前务必检查文件剩余长度,避免
read()超出边界导致failbit置位却不报错
序列化不是“把内存 dump 出去”那么简单。哪怕一个 std::string 字段,背后就涉及堆分配地址、长度、容量三个值,而反序列化时你得重建整个堆状态——这点最容易被当成“小问题”跳过去,结果调试半天才发现是 string 的内部指针没重置。









