You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 20:01:14