c++使用结构中的指针保存和加载游戏
我知道我可以使用:
MyGame game; // the game object
//
ofstream out("mygame.bin", ios::binary);
out.write((char *)&game, sizeof(MyGame));
来保存和加载游戏,但是如果我在 MyGame 结构中有指针怎么办?会只保存指针而不保存它指向的数据吗?
以及:如何解决这个问题?
I know I can use:
MyGame game; // the game object
//
ofstream out("mygame.bin", ios::binary);
out.write((char *)&game, sizeof(MyGame));
to save and load the game, but what if I have pointers inside MyGame structure? will the pointers just be saved but not the data it points to?
and: how to solve this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
您不能只编写指向流的指针并期望它能够神奇地完成。您需要在对象中实现保存/加载方法。例如:
You can't just write pointers to a stream and expect it to be magically done. You need to implement save/load methods in your objects. E.g:
假设您没有覆盖 char * 强制转换,是的,这很可能只保存指针而不保存数据。
您需要的是对象的序列化。您可以提供一种方法来编组位流中的对象状态并将其写出。并且您还需要有方法来恢复状态。
您可以在 wikipedia 上阅读有关序列化的更多信息
Assuming you have not overridden char * cast, yes this will most probably save only pointer and not data.
What you need is Serialization of your object. You can provide a method to marshal the state of object in a bit stream and write that out. And you also need to have method to restore the state back.
You may read more about serialization on wikipedia
Boost 有一个序列化库,内置支持深度指针保存和恢复,以及共享数据指针的正确序列化。
这是一个相当广泛的库,但您不需要编写那么多代码就可以在自己的项目中开始使用它。在我看来,除了最简单的序列化要求之外,其他任何事情都值得学习。
Boost has a serialization library, with built in support for deep pointer save and restore, and proper serialization of pointers to shared data.
It's a rather extensive library, but you don't need to write that much code to start using it in your own projects. Well worth the learning effort for anything but the simplest serialization requirements in my opinion.
您可以重载流输出运算符(
<<
)并流出每个单独的字段(反之亦然)编辑:这是一个完整的示例...
您必须了解这种方法的问题,例如生成的文件将是特定于平台的(即不可移植的)等。
You could overload the stream out operator (
<<
) and stream out each individual field (and vice versa)EDIT: here is a complete example...
You must understand the issues with this approach though, such as the resulting file will be platform specific (i.e. non-portable) etc.
尝试
game.serialize(out);
。在您的序列化成员函数中调用指针成员的序列化。Try
game.serialize(out);
. In your serialize member function call serialize of your pointer members.为需要持久化的每种类型创建一个序列化函数。
为每个成员调用这个。
它实际上类似于通过网络进行序列化或出于调试目的进行可视化。
boost.serialize 可以帮助你。
Make a serializing function per type that needs to be persistent.
Call this for each member.
It is actually similar to serializing over network or visualizing for debug-purposes.
boost.serialize can help you.
仅转储指针值的“天真的”序列化永远不会起作用,因为在反序列化时,这些指针将无效。
解决此类问题的一般方法如下:
serialize()
虚拟函数(我假设所有此类对象最终都派生自相同的对象)基类)。get_serialized_id()
公共函数。该函数将使用静态自动递增变量为每个对象实例生成唯一的 id,但仅限第一次调用(后续调用将仅返回现有值)。现在,在序列化时:
std::map
开始。使用get_serialized_id()
返回的值作为键,将您的game
对象添加到此地图。get_serialized_id()
。serialize()
实现来序列化它。让它像往常一样保留其原始数据。对于通过指针提供的数据,请对指向的每个对象调用 get_serialized_id() ,然后序列化从该对象返回的数字。另外,将该对象添加到地图中。这将导致一堆对象被序列化(以“随机”顺序)以及每个对象的“随机”id。
反序列化时:
std::map
开头。读取已保存文件中的第一项。"Naive" serialization that just dumps the value of pointers is never going to work because, when deserializing, those pointers will be invalid.
The general approach to this kind of problem would go like this:
serialize()
virtual function (I am assuming all such objects will ultimately derive from the same base class).get_serialized_id()
public function. This function will use a static auto-incremented variable to generate a unique id for each object instance, but only the first time it is called (subsequent calls will just return the existing value).Now, when serializing:
std::map<int, YourBaseClass*>
. Add yourgame
object to this map, using the value returned byget_serialized_id()
for the key.get_serialized_id()
.serialize()
. Have it persist its primitive data as usual. For data available through pointers, callget_serialized_id()
on each object pointed to and just serialize the number returned from it. Also, add that object to the map.This will result in a bunch of objects being serialized (in a "random" order) along with each one's "random" id.
When deserializing:
std::map<int, YourBaseClass*>
. Read the first item in your saved file.您所做的是浅复制,如果您的
MyGame
类中有指针,那么深复制是必须的!我建议在 MyGame 中实现一个或一组函数,负责将其自己的数据保存到文件中,您只需要调用它即可。
What you did is shallow copy, if you have pointers in your
MyGame
class, then a deep copy is a MUST!.I suggest implementing a function or a set of functiions inside
MyGame
that will take care of saving its own data to a file,and you will only need to call it.感谢大家快速而好的答案,但是我的一个朋友(正在帮助我的人)告诉我我们应该以另一种方式来做。
我只保存对象的基础知识,然后在函数中重新创建其余部分。
这是一款纸牌游戏,为了保存纸牌堆,我们将仅保存纸牌的 ID(而不是对象),并在从文件中读取 ID 时重新初始化每张纸牌。
Thanks everyone for the fast and good answers, but a buddy of mine (who is helping me on this) told me we should do it in another way.
I just save the basics of the object and we recreate the rest in a function.
It's a card-game and to save the stack of cards we'll be saving the ID of the card only (not the objects) and just re-initializing each card when we read in the ID from the file.