C++二进制文件存储vector数组的正确姿势

不能直接对std::vector对象调用write(),因其含指针等非数据成员;应先写大小再写data()指向的POD元素;非POD类型需自定义序列化;读取须严格按序且校验。

直接 write 整个 vector 内存会出错

不能对 std::vector 对象本身调用 write(),哪怕它底层是连续内存。因为 vector 对象包含指针(data_)、大小(size_)和容量(capacity_)等成员,直接二进制写入会把指针值(如 0x7fffabcd1234)也存进去,读取时这个地址早已失效,且跨平台/跨编译器不兼容。

只序列化 data() 指向的元素数据

真正要保存的是元素内容,不是容器结构。需分两步:先写长度,再写元素数据。适用于 vector 元素是 POD 类型(如 intfloatdoublestruct 无虚函数/非POD成员)的情况。

std::ofstream ofs("data.bin", std::ios::binary);
size_t n = vec.size();
ofs.write(reinterpret_

cast(&n), sizeof(n)); if (!vec.empty()) { ofs.write(reinterpret_cast(vec.data()), vec.size() * sizeof(vec[0])); }

读取时必须严格按写入顺序反向操作

顺序错乱或类型不匹配会导致未定义行为,比如把 size_tint 读,或跳过长度直接读数据,都会让后续全部错位。

  • 先读 size_t n,检查是否为合法值(比如 n > SIZE_MAX / sizeof(T) 就该拒绝)
  • 然后 vec.resize(n),再 read()vec.data()
  • 务必检查 gcount()rdstate(),文件损坏或截断时不能假装成功

非 POD 类型(如 std::string、含指针的 struct)不能直接二进制 dump

std::string 在不同 STL 实现中内存布局不同(SSO 是否启用、内部字段顺序),vector<:string> 直接写 data() 只会保存短字符串的栈内副本或野指针,毫无可移植性。

此时必须自定义序列化逻辑:

  • 对每个 std::string,先写其 size()uint32_t),再写字符数据
  • 对含 std::vector 成员的 struct,递归处理每个字段
  • 考虑用 std::span(C++20)或 char* 显式表达字节序列,避免类型误读

二进制存储看似简单,但一旦涉及长度、对齐、端序、生命周期,细节就藏在读写的每一行 reinterpret_cast 后面。别信“只要内存连续就能直接写”这种直觉。