2012-09-12 55 views
2

我在C++中编写了一个相对较大的项目,并且存在对象删除问题。该项目,准确地说是一个roguelike游戏。C++安全对象删除

我有一个类Npc这是游戏中的每个怪物。它们被创建并存储在一个单独的类Storage<Npc>中,负责其管理(加载,保存,创建,删除等)。每当怪物死亡时,相应的对象npc必须完全删除并销毁。删除对象本身并不是一个问题,我只需要调用Storage<NPC>中的一个方法。问题是代码中包含了很多指向这个已经死亡的npc的指针,现在这些指针是无效的,并且试图使用它们会导致很多问题。例如:

  1. 在他去世前可能会有一个他打算执行的操作。
  2. 他在其上放置唱片的瓷砖上有一个指向他的指针。
  3. 他可能参与过一些连续的活动,比如擒拿某人。

代码中有很多这样的指针,所以几乎不可能简单地跟踪它们。我需要的是确定一个npc已经死亡的方法,并且该地址上没有存储实际的对象,所以仍然有这个指针的代码部分可以充分地对他的死亡作出反应。

我自己也想出了一些想法,但至今没有人似乎真的对我好:

  • 我可以问Storage<NPC>类,如果有这种地址的对象。潜在的问题是,删除对象后,可能会在同一地址分配另一个对象,这会导致错误。
  • 我可以通知所有可能使用无效指针的位置。这是一个坏主意,因为这些地点的数量会随着时间的推移而增加,这样做是一种痛苦。
  • 我可以实现一些版本的智能指针,但我不确定要使用哪一个。

TL;博士版本:我需要一个解决方案,如果一个指针指向会告诉我一个对象,或者它指向的内存空闲块,或者一些其他的对象,原来的对象删除后分配。

+0

每当内存被释放/变得无效时,如何将它设置为'nullptr'? :P – SingerOfTheFall

+0

您已经用答案标记了您的问题:使用智能指针。我建议使用std :: shared_ptr – stefan

+0

@SingerOfTheFall,我猜你想说的是,每当我做'删除pnpc;'我应该'pnpc = 0;'。但是,如果有另一个指针等于'pnpc'被存储在程序中的其他地方,它不会被设置为0,所以我猜这是行不通的。 – Saage

回答

2

如何使用弱指针?如果将Npc存储在std::shared_ptr(C++ 11,对于C++ 03使用std::tr1::shared_ptr)中,则可以创建std::weak_ptr(对于C++ 03,再次使用std::tr1::weak_ptr),其中引用shared_ptr。当shared_ptr实际上删除它的对象时,那么所有的weak_ptrs都能够解决这个问题。

虽然我不得不想知道为什么你要删除Npc s,这些s仍然在其他地方使用(例如仍然有动作)。如果不是试图让所有这些其他参考文献发现您已删除Npc,则只需要Npc在所有参考消失后死亡,然后单独使用shared_ptr(无weak_ptr)将正常工作。

+0

我想用我描述的方法,因为这就是游戏机制的工作原理。 NPC随时可能死亡,而且他不能再执行任何动作或成为地图的一部分,这是非常有意义的。我不想在NPC死后执行任何有意义的代码,并且确保在他死后立即删除相应的对象。 – Saage

+0

@Saage:我想如果一个Npc死了,那么你会主动删除它的动画,并在删除Npc之前删除其在地图上的存在(或者可能作为其销毁的一部分,尽管这可能是一个坏主意),而不是依靠地图和动作列表来实现后来的Npc消失。通过这种方式,您可以执行诸如查询动作列表的大小,并确保实际上是待处理动作的计数。 –

3

根据您提供的信息,我可以建议您实施Observer Pattern。 如果有需要对NPC的死亡作出反应的代码,这种模式是可行的。具有NPC指针参考的代码部分将在NPC死亡时通知他们,并删除指向NPC的指针副本,并对NPC的死亡作出反应(无论如何需要)。在NPC被删除之前,死亡通知会发送给所有observers

通过这种模式,您可以实施诸如“英雄每杀死一个怪物获得50 HP”等机制,并且它很容易扩展。

如果没有代码需要积极响应NPC的死亡,并且只需要处理NPC死亡的情况,那么您也可以使用Kevin Ballard的建议使用shared_ptr

+0

我想我最终会使用'shared_ptr',因为它听起来更简单,但观察者模式是一个好主意,我一定会觉得它很有用,谢谢! – Saage

0

一种选择是在你的班级中包含一个引用计数。当某个其他对象(例如一个房间)要持有一个指向npc的指针时,该房间有责任增加npc的引用计数。现在,不是只是删除一个死的npc,而是将它标记为已死(如果您还没有正确的标记,则通过另一个新的数据成员),并且只有在其引用计数为零时才会删除。房间对象还有责任定期检查该标志,并且如果它了解到npc已经死亡,它会减少其参考计数(如果计数现在为零,将导致死后删除)。