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

分段错误求助:类读写特定结构二进制文件的内存分配问题

二进制文件读写后跨进程析构触发段错误排查

我编写了一个类用于读写包含特定数据结构的二进制文件。同一进程内保存后再加载一切正常,但先保存文件再重启程序加载时,程序能完成所有功能,但结束时触发分段错误,疑似内存分配问题。简化代码如下:

读写文件的类头文件

#ifndef __TESTS_MAP_HH__
#define __TESTS_MAP_HH__
#include <iostream>
#include <fstream>
#include <string>
#include <vector> 
#include <algorithm>
#include <sstream> 
typedef struct test_struct{
    bool test_bool; 
    double test_double; 
    std::vector<double> test_vector; 
} test_struct_t; 
class map
{
private:
    std::string m_path, m_str; 
    double m_double; 
    test_struct m_struct; 
public:
    map(const std::string& a_id);
    void set_str(std::string a_str); 
    void set_double(double a_double); 
    void set_struct(test_struct a_struct);
    void load_file(); 
    void save_file() const;
    void show_file() const;   
    ~map();
};
#endif //__TESTS_MAP_HH__

读写二进制文件的类源文件

#include "map.hh"
map::map(const std::string& a_id)
{
    m_path = a_id + ".bin";
    m_str = "none"; 
    m_double = 0.0; 
    m_struct = {false, 0.0};  
}
void map::set_str(std::string a_str){
    m_str = a_str; 
}
void map::set_double(double a_double){
    m_double = a_double; 
} 
void map::set_struct(test_struct a_struct){
    m_struct = a_struct; 
}
void map::load_file(){
    std::ifstream l_inF;
    l_inF.open(m_path.c_str(), std::ios::binary | std::ios::in);
    l_inF.read((char*)&m_double,sizeof(double));
    l_inF.read((char*)&m_struct,sizeof(test_struct_t));
    size_t str_size; 
    l_inF.read((char*)&str_size, sizeof(str_size));
    m_str.resize(str_size); 
    l_inF.read((char*)&m_str[0], str_size);
    l_inF.close(); 
}
void map::save_file() const{
    std::ofstream l_outF;
    l_outF.open(m_path.c_str(), std::ios::binary | std::ios::out);
    l_outF.write((char*)&m_double,sizeof(double));
    l_outF.write((char*)&m_struct,sizeof(test_struct_t));
    size_t str_size = m_str.size(); 
    l_outF.write((char*)&str_size, sizeof(str_size));
    l_outF.write((char*)&m_str[0], str_size);
    l_outF.close(); 
}
void map::show_file() const{
    std::cout << ">>-----------------------------------------------" << std::endl; 
    std::cout << ">> double        : " << m_double << std::endl; 
    std::cout << ">> double        : " << m_double << std::endl; 
    std::cout << ">> struct.bool   : " << m_struct.test_bool << std::endl;
    std::cout << ">> struct.double : " << m_struct.test_double << std::endl;
    std::cout << ">> struct.vector : " << "size = " << m_struct.test_vector.size() <<  std::endl; 
    std::cout << ">> string        : " << m_str <<  std::endl; 
    std::cout << ">>-----------------------------------------------" << std::endl; 
}   
map::~map(){}

主函数(case1运行正常,case2触发分段错误)

#include "map.hh"
int main(int argc, char const *argv[])
{
    std::string id = "mapfile"; 
    int action = 0; 
    if(argc > 1) action = std::stoi(argv[1]); 
    else {
        std::string input;
        std::cout << "Enter case (1 or 2): "; 
        std::cin >> input;
        action = std::stoi(input);
    } 
    switch (action)
    {
    case 1:
        {
            // This works 100% (no errors and it saves/reads class perfectly)
            std::vector<double> l_vect = {0.1, 0.0, 0.6};
            test_struct save_struct = {true, 5.0, l_vect}; 
            map test_save(id); 
            test_save.show_file(); 
            test_save.set_double(8.0); 
            test_save.set_str("save this string"); 
            test_save.set_struct(save_struct); 
            test_save.show_file(); 
            test_save.save_file(); 
            map test_load(id);
            test_load.load_file();
            test_load.show_file(); 
        }
        break;
    case 2:
        {
            // gives segmentation error at the end of the program
            map test_load(id);
            test_load.load_file();
            test_load.show_file(); 
        }
        break;
    
    default:
        break;
    }
    return 0;
}

问题根源

核心错误在于直接读写包含std::vector的结构体:std::vector内部存储的是指向堆内存的指针、元素数量、容量等元数据,直接将结构体写入文件时,保存的只是指针的内存地址而非实际容器数据。跨进程加载时,旧指针地址在新进程的地址空间中是无效的,当std::vector析构时尝试释放这块无效内存,就会触发分段错误。

同一进程内运行正常只是侥幸——此时保存的指针地址仍在当前进程的有效内存范围内,析构时能正常释放,但这种写法本质上违反了std::vector的内存管理逻辑,属于错误实现。

修复方案

需要手动序列化/反序列化std::vector,不能直接读写整个结构体。修改save_file和load_file函数如下:

修改后的save_file函数

void map::save_file() const{
    std::ofstream l_outF;
    l_outF.open(m_path.c_str(), std::ios::binary | std::ios::out);
    l_outF.write((char*)&m_double,sizeof(double));
    
    // 单独保存结构体中的非容器成员
    l_outF.write((char*)&m_struct.test_bool, sizeof(bool));
    l_outF.write((char*)&m_struct.test_double, sizeof(double));
    
    // 序列化vector:先存大小,再存元素数据
    size_t vec_size = m_struct.test_vector.size();
    l_outF.write((char*)&vec_size, sizeof(vec_size));
    if(vec_size > 0){
        l_outF.write((char*)m_struct.test_vector.data(), vec_size * sizeof(double));
    }
    
    // 保存字符串(当前写法正确,继续保留)
    size_t str_size = m_str.size(); 
    l_outF.write((char*)&str_size, sizeof(str_size));
    l_outF.write((char*)&m_str[0], str_size);
    
    l_outF.close(); 
}

修改后的load_file函数

void map::load_file(){
    std::ifstream l_inF;
    l_inF.open(m_path.c_str(), std::ios::binary | std::ios::in);
    l_inF.read((char*)&m_double,sizeof(double));
    
    // 加载结构体非容器成员
    l_inF.read((char*)&m_struct.test_bool, sizeof(bool));
    l_inF.read((char*)&m_struct.test_double, sizeof(double));
    
    // 反序列化vector:先读大小,再分配空间读取元素
    size_t vec_size;
    l_inF.read((char*)&vec_size, sizeof(vec_size));
    m_struct.test_vector.resize(vec_size);
    if(vec_size > 0){
        l_inF.read((char*)m_struct.test_vector.data(), vec_size * sizeof(double));
    }
    
    // 加载字符串(当前写法正确,继续保留)
    size_t str_size; 
    l_inF.read((char*)&str_size, sizeof(str_size));
    m_str.resize(str_size); 
    l_inF.read((char*)&m_str[0], str_size);
    
    l_inF.close(); 
}

额外注意事项

  • std::string的当前写法是正确的(先存长度再存数据),如果直接读写std::string对象也会出现和std::vector相同的问题,需保持现有逻辑。
  • 若需跨平台使用,要额外处理字节序问题(比如小端/大端转换),避免不同平台间数据解析异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 14:57:22