我有一个名为Game
的课程,其中包含以下内容:
vector<shared_ptr<A>> attr; // attributes
D diff; // differences
vector<shared_ptr<C>> change; // change
我的问题是,如何将这些(保存)写入文件并稍后读取/加载?
我想过在其中使用struct
,只是保存struct
,但我不知道从哪里开始。
这是我到目前为止的尝试,只是试图保存change
。我已经在这个问题上阅读了很多内容,而且我的问题(其中一个,无论如何)在这里似乎是我存储的指针在关闭程序后会无效(因为我也释放它们的事实)在退出之前)。
/* Saves state to file */
void Game::saveGame(string toFile) {
ofstream ofs(toFile, ios::binary);
ofs.write((char *)&this->change, sizeof(C));
/* Free memory code here */
....
exit(0);
};
/* Loads game state from file */
void Game::loadGame(string fromFile) {
ifstream ifs(fromFile, ios::binary);
ifs.read((char *)&this->change, sizeof(C));
this->change.toString(); // display load results
};
任何人都可以指导我正确的方向来序列化这些数据吗?我只想使用标准套餐,所以没有boost
。
感谢。
答案 0 :(得分:1)
我不知道如何实现类A
,C
或D
,但这是第一个问题:如何序列化该类的对象。对于C
案例,您需要实现以下内容:
std::ostream& operator <<(std::ostream& os, const C& c) {
// ... code to serialize c to an output stream
return os;
}
std::istream& operator >>(std::istream& is, C& c) {
// ... code to populate c contents from the input stream
return is;
}
或者,如果您愿意,可以为该课程创建write()
和read()
函数。
好吧,如果你想序列化vector<shared_ptr<C>>
看起来很明显,你不想序列化指针,而是内容。因此,您需要取消引用每个指针并进行序列化。如果在加载之前未知向量的大小(即,并不总是相同),则需要存储该信息。然后,您可以创建一对函数来序列化完整的向量:
std::ostream& operator <<(std::ostream& os, const std::vector<std::shared_ptr<C>>& vc) {
// serialize the size of the vector using << operator
// for each element of the vector, let it be called 'pc'
os << *pc << std::endl; // store the element pointed by the pointer, not the pointer.
return os;
}
std::istream& operator >>(std::istream& is, std::vector<std::shared_ptr<C>>& c) {
// read the size of the vector using >> operator
// set the size of the vector
// for each i < sizeo of the vector, let 'auto &pc = vc[i]' be a reference to the i-th element of the vector
C c; // temporary object
is >> c; // read the object stored in the stream
pc = std::make_shared<C>(c); // construct the shared pointer, assuming the class C has copy constructor
return is;
}
然后,
/* Saves state to file */
void Game::saveGame(string toFile) {
ofstream ofs(toFile);
ofs << change;
....
};
/* Loads game state from file */
void Game::loadGame(string fromFile) {
ifstream ifs(fromFile);
ifs >> change;
};
我知道你还需要解决很多问题。我建议您进行调查以解决这些问题,以便您了解如何解决问题。
答案 1 :(得分:1)
您不仅要保存指针,还要尝试保存shared_ptr
但使用错误的大小。
您需要为所有类编写序列化函数,注意不要只编写非POD类型的原始位。最安全的是始终为所有事物实施逐个成员的序列化,因为你永远不知道未来会带来什么 然后处理它们的集合只是存储有多少它的问题。
C
的示例:
void Game::save(ofstream& stream, const C& data)
{
// Save data as appropriate...
}
void Game::saveGame(string toFile) {
ofstream ofs(toFile, ios::binary);
ofs.write((char *)change.size(), sizeof(change.size());
for (vector<shared_ptr<C>>::const_iterator c = change.begin(); c != change.end(); ++c)
{
save(ofs, **c);
}
};
shared_ptr<C> Game::loadC(ofstream& stream)
{
shared_ptr<C> data(new C);
// load the object...
return data;
}
void Game::loadGame(string fromFile) {
change.clear();
size_t count = 0;
ifstream ifs(fromFile, ios::binary);
ifs.read((char *)&count, sizeof(count));
change.reserve(count);
for (int i = 0; i < count; ++i)
{
change.push_back(loadC(ifs));
}
};
当然缺少所有错误处理 - 您需要添加它。
至少从文本存储开始(使用<<
和>>
)而不是二进制文件,这是一个好主意。当你可以在文本编辑器中编辑它时,更容易找到错误或者处理已保存的状态。
答案 2 :(得分:1)
编写自己的序列化是一项相当大的挑战。即使你不使用boost serializatoin,我也会建议你学习如何使用它并理解它是如何工作的,而不是自己发现它。
在序列化时,你最终会得到一个数据缓冲区,其内容你的想法很模糊。您必须保存能够恢复它所需的一切。你大块读了它。示例(未编译,未经测试且不时尚):
void save(ostream& out, const string& s)
{
out << s.size();
out.write(s.c_str(), s.size());
}
void load(istream& in, string& s)
{
unsigned len;
in >> len;
s.resize(len);
in.read((char*)s, len);
}
struct Game
{
void save(ostream& out)
{
player.save(out);
};
void load(istream& in)
{
player.load(in);
}
};
struct Player
{
void save(ostream& out)
{
// save in the same order as loading, serializing everything you need to read it back
save(out, name);
save(out, experience);
}
void load(istream& in)
{
load(in, name);
load(in, experience); //
}
};
我不知道为什么你会这样做而不是使用提升,但这些是你应该考虑的一些情况: - 类型 - 你必须找到一种方法来了解什么&#34;变化类型&#34;你真的在那里。 - 一个字符串(矢量,无论如何) - 大小+数据(然后你从字符串读回的第一件事是长度,你调整它的大小并复制&#34;长度&#34;字符数) - 指针 - 保存指针指向的数据,然后在反序列化时必须分配它,构造它(通常是默认构造)并读回数据并将成员重置为它们各自的值。注意:您必须避免内存泄漏。 - 多态指针 - 你必须知道指针实际指向的是什么类型,你必须构造派生类型,保存派生类型的值...所以你必须保存类型信息 - 空指针...您必须区分空指针,以便您知道不需要进一步从流中读取数据。 - 版本控制 - 您必须能够在添加/删除字段后读取数据
你得到一个完整的答案太多了。