不能直接用fread或std::ifstream::read读取含裸指针的结构体,因指针存储的是内存地址,序列化后该地址加载时已失效,导致段错误;必须手动深拷贝指针所指数据并统一处理读写顺序与字节序。

直接读取含指针结构体的二进制会崩溃
不能直接用 fread 或 std::ifstream::read 读取含裸指针(如 int*、char*)的结构体。指针字段本身只存地址值,序列化后写入文件的是该地址数字(比如 0x7fffe8a12340),加载时这个地址大概率已失效或被占用,解引用必然 segmentation fault 或读到垃圾数据。
这不是“读得不对”,而是“语义上就不支持”——C++ 的 POD 结构体二进制序列化仅对纯数据类型(int、double、数组、嵌套 POD)有效,指针破坏了数据自包含性。
深拷贝必须手动处理指针成员
要持久化含指针的结构体,必须把指针指向的**实际数据**一并写入文件,并在读取时重新分配内存、逐字节还原内容。没有编译器自动帮你做这件事。
典型做法是拆成两步:先写元信息(如指针长度、偏移),再写真实数据块;读取时按顺序反向恢复。
立即学习“C++免费学习笔记(深入)”;
-
struct Data { int* arr; size_t len; };→ 写文件时先写len(sizeof(size_t)字节),再写arr指向的len * sizeof(int)字节 - 读取时先读
len,new int[len]分配内存,再读对应字节数到新内存 - 别忘了读写顺序严格一致,大小端需统一(跨平台时用
htons/ntohl等)
浅拷贝陷阱:memcpy 不能用于含指针结构体
即使不涉及文件 I/O,仅用 memcpy(&dst, &src, sizeof(Data)) 复制含指针的结构体,也只会复制指针值本身,导致 dst.arr 和 src.arr 指向同一块内存。后续任意一方 delete[] 都会让另一方悬空。
这类错误在调试时极难复现,尤其当两个对象生命周期不同步时。
- 禁止对含裸指针的结构体使用
memcpy、std::bit_cast、std::memcpy - 必须定义显式的拷贝构造函数和
operator=,对每个指针成员执行new+std::copy - 更稳妥的做法是改用
std::vector、std::string等 RAII 容器,它们自带正确深拷贝语义
用 std::vector 替代裸指针最省心
绝大多数场景下,“结构体里放指针”只是历史习惯或对 C 兼容的执念。现代 C++ 中,用 std::vector 不仅避免手写序列化逻辑,还能自动管理内存、支持移动语义、兼容标准流操作。
例如:
struct Data {
std::vector<int> arr;
// 无需写构造/析构/拷贝函数
};
// 序列化:
std::ofstream os("data.bin", std::ios::binary);
size_t sz = data.arr.size();
os.write(reinterpret_cast<const char*>(&sz), sizeof(sz));
os.write(reinterpret_cast<const char*>(data.arr.data()), sz * sizeof(int));
// 反序列化同理,先读 sz,再 resize 后 read
真正需要裸指针的场景极少(比如对接硬件寄存器、零拷贝网络收包),此时务必明确责任边界:谁分配、谁释放、谁序列化、谁反序列化——这些逻辑一旦混在一起,出问题几乎无法调试。


















