C++含string结构体的二进制读写(适配单链表,解决读取报错)
问题根因定位
你当前遇到的报错根源并非仅Read函数内的resize逻辑错误,首先是Save函数的序列化设计本身存在根本性缺陷:
std::string不属于POD(平凡可复制)类型,结构体中的string成员本身不存储连续的字符串字符内容,仅保存指向堆内存中字符串内容的指针、当前字符串长度、堆块容量三类运行时元信息。- 你在Save函数中直接把整个
Data结构体的内存数据写入文件的操作,实际落盘的是这些临时的内存地址、容量数值,而非字符串本身的字符内容——哪怕你提前记录了字符串长度,这些堆地址值在程序重启后属于完全无效的悬空地址,根本无法还原原始字符串。 - Read函数中对string做resize的逻辑本身方向正确,但由于Save端写入的不是有效字符串内容,必然会出现读取偏移错位、内存越界访问的运行报错。
修复实现方案
二进制读写逻辑必须严格对称,绝对不能对包含string的结构体做整块内存的二进制序列化,修正后的读写逻辑如下:
- 修正Save端写入逻辑(删除直接整块写结构体内存的错误操作,和你已有的长度记录逻辑对齐):
遍历单链表节点时,按照固定顺序依次写入:name成员的字符串长度surname成员的字符串长度grade成员的int值name对应的实际字符序列surname对应的实际字符序列
核心实现代码参考:
// 单链表节点遍历内的写入逻辑 size_t nameLen = curr->data.name.size(); size_t surLen = curr->data.surname.size(); note.write(reinterpret_cast<const char*>(&nameLen), sizeof(nameLen)); note.write(reinterpret_cast<const char*>(&surLen), sizeof(surLen)); note.write(reinterpret_cast<const char*>(&curr->data.grade), sizeof(curr->data.grade)); note.write(curr->data.name.c_str(), nameLen); note.write(curr->data.surname.c_str(), surLen); - 修正Read端读取逻辑(调整resize的执行时机,和Save的写入顺序严格对齐):
按照Save端的固定顺序依次读取字段,读完长度后先给对应string成员分配目标长度的内存空间,再把文件中读到的字符流写入string的内部缓冲区,不要先整块读入结构体内存再单独resize。
核心实现代码参考:// 读取文件构造新链表节点的逻辑 size_t nameLen, surLen; int grade; rfrom.read(reinterpret_cast<char*>(&nameLen), sizeof(nameLen)); rfrom.read(reinterpret_cast<char*>(&surLen), sizeof(surLen)); rfrom.read(reinterpret_cast<char*>(&grade), sizeof(grade)); Data nodeData; nodeData.grade = grade; // 先完成内存分配 nodeData.name.resize(nameLen); nodeData.surname.resize(surLen); // 再将读到的字符直接写入已分配的缓冲区 rfrom.read(nodeData.name.data(), nameLen); rfrom.read(nodeData.surname.data(), surLen);
避坑提示
- 禁止对包含
std::string、裸指针、自定义非POD成员的结构体做整块内存的二进制落盘,这类操作写入的是进程运行时的临时内存地址,跨程序运行周期完全不可复用 - 读写全流程的字段顺序、字段类型、字段占用字节长度必须严格一致,一旦出现任意一步的顺序错位,后续所有读取的文件偏移量都会完全错乱,直接触发内存访问异常
- 每完成一次读写操作,需要检查文件流的状态位,确认没有提前触达EOF、读写长度不足的异常,避免残缺数据导致的未定义行为
内容的提问来源于stack exchange,提问作者Nconst
相关产品推荐
相关产品推荐

