我是C ++的新手,我目前正在开发一款游戏。在游戏中,随着时间的推移我会产生随机敌人,我正在使用std :: vector来做到这一点。我以为我可以使用像
这样的东西enemies.push_back(new Enemy(random_x, randomY));
在一个循环中,但现在在我看来,这可能会导致内存泄漏,因为我没有删除指针。所以我想学习如何防止内存泄漏;我应该找到一种方法来删除我创建的所有敌人,还是应该做一些完全不同的事情?
答案 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_shared
或std::make_unique
在堆上创建对象。
答案 1 :(得分:0)
如果在没有首先释放后备存储的情况下失去对象的访问权限,则只有内存泄漏。这不是这里的情况,因为你只需走过enemies
集合就可以找到所有这些敌人。
据推测,在某些时候你会从列表中删除敌人(例如,当你在游戏中杀死敌人时)。此时你应该删除它们并回收内存。