[英]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结构一样)。 您不能只是按位读取和写入其内存并期望它能工作。 string
和vector
都不是POD,它们保留指向其动态分配数据的指针。 当读回这些内容时,尝试访问无效的内存将导致段错误。 而且, string
和vector
的内容实际上根本没有保存,因为它们不在对象的内存布局之内(它有时可能与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.