std::vector二进制序列化需先写size()(uint64_t)再写data(),仅限POD类型;必须用binary模式、判空、固定宽度整数、处理字节序与对齐。

std::vector 二进制序列化必须手动处理 size() 和 data()
不能直接 write() 整个 std::vector 对象——它内部是动态分配的指针,sizeof(std::vector) 固定(通常 24 字节),写进去毫无意义。真正要持久化的,是元素数据本身,以及长度信息,否则读取时无法知道该读多少字节。
典型做法是:先写入 size()(用固定宽度整数,如 uint64_t),再写入 data() 指向的原始内存块。注意类型必须是 POD(Plain Old Data);含指针、虚函数、非平凡构造/析构的类(如 std::string、std::vector<std::string>)不能这样直接二进制 dump。
-
std::vector<int>、std::vector<double>、std::vector<uint8_t>可以直接序列化 - 写入前务必检查
v.data()是否非空(空 vector 的data()可能为nullptr,但size()为 0,此时只写 size 即可) - 推荐用
uint64_t存 size,避免 32 位平台溢出;读取端也必须用相同宽度解析
用 std::ofstream::write() 写二进制需设置 std::ios::binary
默认文本模式会把 \n 转成 \r\n(Windows),破坏二进制一致性。不加 binary 标志,写出来的文件大概率读不出来或数据错位。
正确写法示例:
立即学习“C++免费学习笔记(深入)”;
std::ofstream ofs("data.bin", std::ios::out | std::ios::binary);
uint64_t n = v.size();
ofs.write(reinterpret_cast<const char*>(&n), sizeof(n));
if (!v.empty()) {
ofs.write(reinterpret_cast<const char*>(v.data()), v.size() * sizeof(v[0]));
}- 必须用
reinterpret_cast<const char*>转换指针,write()第二个参数要求是const char* - 写
data()前一定要判空,否则对空 vector 解引用v.data()是未定义行为(尽管多数实现返回nullptr,但write(nullptr, 0)在某些标准库下可能 crash) - 确保
ofs打开成功且未发生failbit——建议后续加if (!ofs) { /* error */ }
读取时顺序必须严格匹配:先读 size(),再按 size 分配并读 data()
读取逻辑不是“反向执行写操作”那么简单:如果写入的 size 是 0,你不能跳过读 data() 步骤——你仍要读 size 字段,只是后续不读元素。顺序错乱(比如先读元素再读 size)会导致整个结构解析失败。
读取示例:
std::ifstream ifs("data.bin", std::ios::in | std::ios::binary);
uint64_t n = 0;
ifs.read(reinterpret_cast<char*>(&n), sizeof(n));
std::vector<int> v(n); // 直接构造指定大小
if (n > 0) {
ifs.read(reinterpret_cast<char*>(v.data()), n * sizeof(int));
}- 用
std::vector<T>(n)构造而非reserve()+push_back(),确保内存连续且已初始化(对 POD 类型,vector(n)默认值初始化,不影响二进制内容) -
read()不保证一次读完全部字节,尤其在流异常或文件截断时;应检查gcount()或用ifs.gcount() == sizeof(n)验证 - 若读取
size后发现超出合理范围(如 > 1GB 元素),应提前终止,防止 OOM
跨平台兼容性陷阱:字节序与对齐问题必须显式处理
同一份二进制文件,在 x86(小端)和 ARM64(可能大端)机器上直接读,uint64_t 值会完全错误。C++ 标准不规定字节序,也不保证 struct 对齐一致。
- 写入前统一转为网络字节序(大端):
htobe64(n)(Linux/BSD)或手动实现;读取时用be64toh() - 不要依赖
sizeof(T)在不同平台恒定——虽然int常见是 4 字节,但标准只要求 ≥2;明确用int32_t、uint64_t等固定宽度类型 - 如果 vector 元素是自定义 struct,必须确保其满足
std::is_standard_layout_v<T>且无 padding(用static_assert检查sizeof(T) == offsetof(...)),否则二进制布局不可靠
最易被忽略的是:哪怕代码在本机读写都正常,一旦部署到异构环境或未来升级编译器,未处理字节序和类型宽度的二进制格式会立刻失效。



















