C++读写含vector的struct二进制文件触发读取访问违例的原因与解决
含vector的struct读写二进制文件出现读取访问违例的原因与修复
错误原因
C++的vector是动态容器,它的内部结构并非直接存储元素数据,而是包含三个核心元数据:指向堆内存的指针(实际元素存在这里)、当前元素数量(size)、容器容量(capacity)。
当你用fwrite直接写入整个struct A时,只会把这些元数据写入文件,完全没有保存vector里的实际int值。读取时,fread把旧的指针值读入新的vector对象,这个指针指向的内存早已失效(要么不属于当前程序,要么已被系统释放),此时调用ret.int_vector.at(0)访问无效内存,必然触发读取访问违例。
而当struct里是int这类值类型时,所有数据都在struct的内存块内,直接读写自然不会有问题。
修复方法
方法1:手动实现序列化逻辑(C风格FILE)
自己控制vector的读写流程:先写入vector的元素数量,再写入所有元素;读取时先读数量,再逐个读取元素填充vector。同时必须用二进制模式打开文件,避免文本模式的格式转换损坏数据。
修改后的完整代码:
#pragma warning(disable : 4996) #include <iostream> #include <stdio.h> #include <vector> using namespace std; struct A { vector<int> int_vector; // 将struct写入文件 bool write(FILE* file) const { // 先写入vector的元素数量 size_t elem_count = int_vector.size(); if (fwrite(&elem_count, sizeof(elem_count), 1, file) != 1) { return false; } // 写入所有元素 if (!int_vector.empty() && fwrite(int_vector.data(), sizeof(int), elem_count, file) != elem_count) { return false; } return true; } // 从文件读取struct bool read(FILE* file) { size_t elem_count; if (fread(&elem_count, sizeof(elem_count), 1, file) != 1) { return false; } // 调整vector大小并读取元素 int_vector.resize(elem_count); if (!int_vector.empty() && fread(int_vector.data(), sizeof(int), elem_count, file) != elem_count) { return false; } return true; } }; int main() { A a1; a1.int_vector.push_back(3); // 二进制模式写入:wb FILE* outfile = fopen("save.dat", "wb"); if (outfile == NULL) { cout << "error opening file for writing " << endl; return 1; } if (!a1.write(outfile)) { cout << "write failed" << endl; fclose(outfile); return 1; } fclose(outfile); A ret; // 二进制模式读取:rb FILE* infile = fopen("save.dat", "rb"); if (infile == NULL) { cout << "error opening file for reading " << endl; return 1; } if (!ret.read(infile)) { cout << "read failed" << endl; fclose(infile); return 1; } fclose(infile); cout << ret.int_vector.at(0) << endl; return 0; }
方法2:使用C++标准文件流(更推荐)
用std::ofstream和std::ifstream的二进制模式,配合重载运算符实现序列化,更符合C++的编码风格。
示例代码:
#include <iostream> #include <fstream> #include <vector> using namespace std; struct A { vector<int> int_vector; }; // 重载写入运算符,实现A的序列化 ostream& operator<<(ostream& os, const A& a) { size_t elem_count = a.int_vector.size(); os.write(reinterpret_cast<const char*>(&elem_count), sizeof(elem_count)); if (elem_count > 0) { os.write(reinterpret_cast<const char*>(a.int_vector.data()), elem_count * sizeof(int)); } return os; } // 重载读取运算符,实现A的反序列化 istream& operator>>(istream& is, A& a) { size_t elem_count; is.read(reinterpret_cast<char*>(&elem_count), sizeof(elem_count)); a.int_vector.resize(elem_count); if (elem_count > 0) { is.read(reinterpret_cast<char*>(a.int_vector.data()), elem_count * sizeof(int)); } return is; } int main() { A a1; a1.int_vector.push_back(3); ofstream outfile("save.dat", ios::binary); if (!outfile.is_open()) { cout << "error opening file for writing " << endl; return 1; } outfile << a1; outfile.close(); A ret; ifstream infile("save.dat", ios::binary); if (!infile.is_open()) { cout << "error opening file for reading " << endl; return 1; } infile >> ret; infile.close(); cout << ret.int_vector.at(0) << endl; return 0; }
内容的提问来源于stack exchange,提问作者Håkan Troberg
相关产品推荐
相关产品推荐

