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

C++将vector保存到二进制文件读取时触发Segmentation fault段错误

问题描述

编写程序将列表数据保存为二进制文件,预期实现两个效果:一是避免数据被随意篡改,二是获得比文本文件更小的存储体积。采用三层嵌套vector<vector<vector<string>>>结构存储数据,但读取二进制文件时触发Segmentation fault(段错误)。

错误写入代码

#include <iostream>
#include <fstream>
#include <vector>

using namespace std;

vector<vector<vector<string>>> test;

int main() {
    
    test.push_back({{"Hello"}});
    
    cout << test[0][0][0];
    
    ofstream otst("test.bin",ios::binary);
    
    otst.write((char*)&test,sizeof(test));
    
    return 0;
}

错误读取代码

#include <iostream>
#include <fstream>
#include <vector>

using namespace std;

vector<vector<vector<string>>> test;

int main() {
    
    ifstream tst("test.bin",ios::binary);
    
    tst.read((char*)&test,sizeof(test));
    return 0;
}
错误根因

直接将vector对象本身的内存块写入文件的写法完全错误:

  • vector、string都属于动态管理堆内存的容器,对象本身只存储三类元信息:指向堆上真实数据的指针、当前元素数量、已分配容量,真实的字符串内容、各层vector存储的元素都存在对象之外的堆内存上。
  • 上述写法只把容器对象的元信息(包括失效的堆指针)写入了文件,根本没有保存任何实际业务数据。
  • 读取时直接把文件里存的旧进程的指针值覆盖到新的容器对象上,这些指针地址不属于当前运行进程的合法内存空间,一旦访问就会触发段错误。就算不崩溃,读到的也都是无效内存数据。
修复方案

二进制存储动态容器必须做结构化序列化:按固定顺序逐层写入容器的长度、每个元素的实际内容,读取时按完全相同的顺序,先读长度再逐个还原元素,不能直接拷贝容器对象的内存布局。

修复后的写入代码

#include <iostream>
#include <fstream>
#include <vector>
#include <string>

using namespace std;

int main() {
    vector<vector<vector<string>>> test;
    test.push_back({{"Hello"}});
    cout << test[0][0][0] << endl;

    ofstream otst("test.bin", ios::binary);
    // 逐层写入尺寸,再写实际内容
    size_t l1_size = test.size();
    otst.write((char*)&l1_size, sizeof(l1_size));
    for (auto& l2 : test) {
        size_t l2_size = l2.size();
        otst.write((char*)&l2_size, sizeof(l2_size));
        for (auto& l3 : l2) {
            size_t l3_size = l3.size();
            otst.write((char*)&l3_size, sizeof(l3_size));
            for (auto& s : l3) {
                size_t str_len = s.size();
                otst.write((char*)&str_len, sizeof(str_len));
                otst.write(s.data(), str_len);
            }
        }
    }
    otst.close();
    return 0;
}

修复后的读取代码

#include <iostream>
#include <fstream>
#include <vector>
#include <string>

using namespace std;

int main() {
    vector<vector<vector<string>>> test;
    ifstream tst("test.bin", ios::binary);

    // 按写入顺序逐层读尺寸,再读内容还原结构
    size_t l1_size;
    tst.read((char*)&l1_size, sizeof(l1_size));
    test.resize(l1_size);
    for (size_t i = 0; i < l1_size; i++) {
        size_t l2_size;
        tst.read((char*)&l2_size, sizeof(l2_size));
        test[i].resize(l2_size);
        for (size_t j = 0; j < l2_size; j++) {
            size_t l3_size;
            tst.read((char*)&l3_size, sizeof(l3_size));
            test[i][j].resize(l3_size);
            for (size_t k = 0; k < l3_size; k++) {
                size_t str_len;
                tst.read((char*)&str_len, sizeof(str_len));
                string s(str_len, '\0');
                tst.read(s.data(), str_len);
                test[i][j][k] = move(s);
            }
        }
    }
    tst.close();

    // 验证读取结果
    cout << test[0][0][0] << endl;
    return 0;
}

注意:如果需要跨平台兼容,还要额外处理整型的大小端、不同平台size_t长度不一致的问题,同平台下上述代码可以正常运行。

内容的提问来源于stack exchange,提问作者Star Dev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 21:36:25