繁体   English   中英

GCC下的对象加载段错误

[英]Object loading segfault under GCC

这些方法应该保存并加载与之关联的整个对象。 当我通过gcc在Linux下编译程序时,保存似乎可以正常工作,但在加载时会出现段错误。 当我通过Visual Studio编译器在Windows下编译它时,它的工作就像梦一样。 我不确定有什么区别,但是我有一种直觉,那就是它涉及到一些gcc怪异之处。

两种方法:

void User::SaveToFile()
{
  ofstream outFile;
  string datafile_name = username + "_data";
  outFile.open(datafile_name.c_str(), ios::binary);
  outFile.write((char*)this, sizeof(*this));
}
void User::LoadFromFile(string filename)
{
  ifstream inFile;
  inFile.open(filename.c_str(), ios::binary);
  inFile.read((char*)this, sizeof(*this));
}

声明:

class User
{
private:
  string username;
  string realname;
  string password;
  string hint;
  double gpa;
  vector<Course> courses;
public:
  double PredictGPA();
  void ChangePassword();
  void SaveToFile();
  void LoadFromFile(string filename);

  void SetUsername(string _username){username = _username;}
  string GetUsername(){return username;}
  void SetRealname(string _realname){realname = _realname;}
  string GetRealname(){return realname;}
  void SetPass(string _password){password = _password;}
  string GetPass(){return password;}
  void SetHint(string _hint){hint = _hint;}
  string GetHint(){return hint;}
};

您将需要一种序列化和反序列化您的类的方法。 像这样阅读时,您的类无法神奇地成为对象。

相反,您需要提供在加载/保存类时调用的函数,这些函数以您选择的某种格式(例如XML)存储类。

所以代替

outFile.write((char*)this, sizeof(*this));

具有一些成员函数,可以将其转换为具有某种格式的字符串,该格式可以在加载时轻松解析(或某种二进制格式,可以轻松找到),然后保存。

outFile.write(this->myserialize(), mysize);

您的class User不是POD类型,也不是Plain Old Data类型(就像C结构一样)。 您不能只是按位读取和写入其内存并期望它能工作。 stringvector都不是POD,它们保留指向其动态分配数据的指针。 当读回这些内容时,尝试访问无效的内存将导致段错误。 而且, stringvector的内容实际上根本没有保存,因为它们不在对象的内存布局之内(它有时可能与SBO一起用于string ,但其公正但偶然且仍然不确定地执行它)。

你不能这样写到string中。 一方面,它通常动态地存储其数据,即根本不存储在对象内部;另一方面,您不应依赖于其任何特定的布局。

向量也有类似的问题,您似乎根本没有考虑字节顺序和填充。

简而言之,您所做的假设并不成立。

通常,不要在字节级别上弄乱复杂的(非POD)对象。 而是使用某种文本格式进行序列化,使用对象的公共成员函数提取并恢复其状态。

您是否考虑过JSON?

诸如字符串之类的东西可能包含指针-在这种情况下,您的方法可能会出错。

您需要序列化数据-即将其转换为一系列字节。

然后,在读取数据时,您只需读取字节,然后从中创建对象。 新的指针将是正确的。

如果您选择这条路线,我会写一个字符串的长度,而不是用null终止它。 加载时更容易分配。 有很多要考虑的二进制格式。 每个字段应具有某种类型的ID,以便在错误位置或程序的不同版本中都可以找到它。 同样在文件的开头,写出您正在使用的字节序,整数的大小等。或者确定所有内容的标准大小和字节序。 我经常为网络和文件存储编写这样的代码。 有更好的现代方法。 还可以考虑使用缓冲区并创建Serialize()函数。

好的现代替代品包括:SQLite3,XML,JSON

未经测试的示例:

class object
{

Load()
{
  ifstream inFile;
  int size;

  inFile.open("filename", ios::binary);

  inFile.read(&size, 4);  
  stringA.resize(size);
  inFile.read(&stringA[0], size);

  inFile.read(&size, 4);  
  stringB.resize(size);
  inFile.read(&stringB[0], size);

  inFile.close();          //don't forget to close your files
}
Save()
{
  ofstream outFile;
  int size;

  outFile.open("filename", ios::binary);

  size = stringA.size();   
  outFile.write(&size, 4);
  outFile.write(&stringA[0], size);

  size = stringB.size();       
  outFile.write(&size, 4);
  outFile.write(&stringA[0], size);
  outFile.close();
}

private:
std::string stringA
std::string stringB
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM