将用户定义的数据类型保存到C ++文件中

时间:2018-11-23 17:42:42

标签: c++ fwrite fread

我有一个这样的班级:

struct SomeClass{

    SomeClass(){}

    SomeClass(const SomeClass& rhs):
    _m1(rhs._m1),
    _m2(rhs._m2),
    _m3(rhs._m3),
    _m4(rhs._m4){}

    SomeClass& operator=(const SomeClass& rhs){
    // same as above
    return *this;
    }

    int _m1;
    std::vector<int> _m2;
    std::vector<int> _m3;
    int _m4;
};

在程序的某个时刻,我想保存存储在SomeClass对象中的数据以供以后使用:

    SomeClass someObj = arr->getBest(); // arr is a pointer to AnotherClass,
                                        // in which different SomeClass
                                        // objects are initialized and then
                                        // involved in various 
                                        // computations in AnotherClass, 
                                        // finally the best one SomeClass 
                                        // object will be save here
    fwrite(&someObj, sizeof(SomeClass), 1, saveFile);

将文件保存到saveFile后,我尝试读取该文件并出现错误:

    SomeClass readingSomeObj;
    fread(&readingSomeObj, sizeof(SomeClass), 1, savedFile));

编译器抱怨“访问冲突读取位置0x ...”。通过查看VS中的本地人,我发现readingSomeObj的其他两个字段,即_m1_m4中有值,但没有_m2_m3 ,在VS中显示为“无法读取内存”。 vs error prompt

它进一步将问题与SomeClass(特别是此行_m2(rhs._m2),)相关。

但是当我在行someObj中保存fwrite(&someObj, sizeof(SomeClass), 1, saveFile);时,我确实看到_m2的两个成员_m3someObj具有值(通过悬停我的鼠标移到&someObj上。

我不知道出了什么问题。我的猜测是SomeClass的构造函数存在问题,但是作为C ++的新手,我不知道如何纠正它。在程序的其他部分,我使用了SomeClass的空构造函数来初始化AnotherClass的成员。但是除了这个保存/读取部分,一切都运行良好。我正在寻找您的慷慨帮助,并感谢您一百万!

2 个答案:

答案 0 :(得分:5)

您已经对数据类型做出了很多不成立的假设。最令人震惊的是,其所有字节都存储在内存中的“行”中,彼此相邻,这是逐块复制和读取可以工作的唯一方法。

这可能适用于POD(取模对齐和字节顺序考虑),但不适用于vector之类的复杂数据类型,该数据类型指向实际存储在其他位置(通过动态分配)的“真实”数据。

您的反序列化向量几乎完全由长期以来无效的指针值组成。

您的序列化例程必须比这更智能。最终,没有“一种”方法可以做到这一点。您可以定义自己的格式,也可以使用一些现成的序列化解决方案,该解决方案已经具有支持标准容器的格式。

您可以使用Google“ C ++类序列化”获得一些想法。

答案 1 :(得分:3)

您不能像这样对向量进行序列化。它们已经分配了内存,因此可以执行以下操作:

  • 将整数存储到文件中
  • 存储第一个向量的大小
  • 存储第一个向量的内容
  • 对第二个向量执行相同的操作

然后,当您读取文件时:

  • 读取您的两个整数
  • 读取您的第一个向量大小,分配向量
  • 读取您的第一个向量的值
  • 对第二个向量执行相同操作。

您还可以使用Boost.Serialization之类的序列化库,以更可靠的方式处理这些问题。