如何删除尚未分配给对象的指针

时间:2014-02-23 09:57:14

标签: c++ pointers vector game-engine

我是C ++的新手,我目前正在开发一款游戏。在游戏中,随着时间的推移我会产生随机敌人,我正在使用std :: vector来做到这一点。我以为我可以使用像

这样的东西
enemies.push_back(new Enemy(random_x, randomY));

在一个循环中,但现在在我看来,这可能会导致内存泄漏,因为我没有删除指针。所以我想学习如何防止内存泄漏;我应该找到一种方法来删除我创建的所有敌人,还是应该做一些完全不同的事情?

2 个答案:

答案 0 :(得分:3)

有多种方法可以解决这个问题。

您可以使用原始指针,如std::vector<Enemy*>中所示,然后您需要在删除它们时将其删除:

delete *pos; // pos is an iterator pointing to the element to be deleted
enemies.erase(pos);

但是,这不是用C ++处理事情的方法。

如果您希望在没有访问列表的情况下传递“敌人”,则可以使用shared_ptr,如std::vector<std::shared_ptr<Enemy>>中所示。然后你只需要擦除,只要没有指向敌人的shared_ptr存在,就会自动释放你的记忆。

enemies.erase(pos); // Nothing more needed, if someone still has a shared_ptr-copy 
                    // of the enemy it will stay in memory until that reference is gone

如果您始终使用列表访问敌人,您甚至可以使用std::unique_ptr。但在这种情况下,最好采用最简单的形式:std::vector<Enemy>。这样您就不必致电new。但这也使您无法使用多态,并且副本可能非常昂贵,具体取决于您的Enemy - 类。

为什么多态不起作用?

std::vector<Enemy>通过复制将完整的Enemy存储在内存中。例如,如果Enemy在内存中占用8个字节,并且在向量中有5个敌人,理论上它将占用40个字节的内存(可能需要更多,但这是特定于实现的)

| Idx0  | Idx1  | Idx2  | Idx3  | Idx4 |
[Enemy1][Enemy2][Enemy3][Enemy4][Enemy5]
   8b      8b      8b      8b      8b

如果你试图存储一个派生的ExtraToughEnemy对象,在3号位置添加了属性,需要说4个额外的字节,它将无法工作,因为向量中的每个条目都必须具有相同的大小。

| Idx0  | Idx1  | Idx2  | Idx3  | Idx4 |
[Enemy1][Enemy2][ExtraToughEnemy3][Enemy4][Enemy5]
   8b      8b           12b          8b      8b

如果使用指针,则可以避免此问题,因为每个指针对象具有相同的大小,但可以指向不同的派生对象。

|  Idx0  |  Idx1  |  Idx2  |  Idx3  |  Idx4 |
[Enemy1*][Enemy2*][Enemy3*][Enemy4*][Enemy5*]
   4b       4b       4b       4b       4b

基类指针可以指向任何基类或派生对象。您必须使用强制转换来访问Enemy3*的额外属性。

关于共享指针和唯一指针的注意事项:

如果您使用它们,您可以考虑(取决于您的编译器),甚至完全跳过使用new并使用std::make_sharedstd::make_unique在堆上创建对象。

答案 1 :(得分:0)

如果在没有首先释放后备存储的情况下失去对象的访问权限,则只有内存泄漏。这不是这里的情况,因为你只需走过enemies集合就可以找到所有这些敌人。

据推测,在某些时候你会从列表中删除敌人(例如,当你在游戏中杀死敌人时)。此时你应该删除它们并回收内存。