这些方法应该保存并加载与其关联的整个对象。当我通过gcc在Linux下编译程序时,保存似乎工作但加载时会出现段错误。当我在Windows下通过Visual Studio编译器编译它时,它就像一个梦想。我不确定这些差异是什么,但我有一种预感,它涉及一些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;}
};
答案 0 :(得分:2)
您需要一种方法来序列化和反序列化您的类;当你以这种方式阅读它时,你的类不会神奇地成为一个对象。
相反,您需要提供在加载/保存您的类时调用的函数,这些函数以您选择的某种格式存储类,例如XML。
所以而不是
outFile.write((char*)this, sizeof(*this));
有一些成员函数将它转换为一个字符串,你可以在加载它时轻松解析一些格式(或者你发现的一些二进制格式更容易),然后保存它。
outFile.write(this->myserialize(), mysize);
答案 1 :(得分:2)
您的class User
不是POD类型,它不是普通旧数据类型(如C结构所示)。你不能只按位读取和写入其内存并期望它能够正常工作。 string
和vector
都不是POD,它们会保留指向动态分配数据的指针。读取这些内容时,尝试访问无效内存将导致段错误。更重要的是,string
和vector
的内容实际上并没有被保存,因为它们不在对象的内存布局中(有时可能与string
一起使用SBO,但它只是偶然但仍然没有定义去做。)
答案 2 :(得分:1)
你不能这样写string
。一方面,它通常动态地存储数据,即根本不存储在对象内部,另一方面,你不应该依赖它的任何特定布局。
向量存在类似问题,您似乎根本没有考虑字节顺序和填充。
简单地说,你做的假设不成立。
通常,不要在字节级别上混淆复杂(非POD)对象。使用某些文本格式进行序列化,使用对象的公共成员函数来提取和恢复其状态。
你考虑过JSON吗?
答案 3 :(得分:1)
像字符串之类的东西可能包含指针 - 在这种情况下,你的方法可能会出现严重错误。
您需要序列化数据 - 即。将其转换为一系列字节。
然后在读取数据时,您只需读取字节,然后从中创建对象。新指针是正确的。
答案 4 :(得分:0)
如果你留在这条路线上,我会写字符串的长度而不是null终止它。在加载时更容易分配。有很多以二进制格式考虑。每个字段都应该有某种类型的ID,以便在错误的位置或程序的不同版本中找到它。同样在文件的开头写下你正在使用的endianess和整数的大小等。或者决定一切的标准大小和endianess。我总是用它来编写这样的代码来进行网络和文件存储。有更好的现代方法。还要考虑使用缓冲区并创建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
};