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

How to delete pointer which has not been assigned to an object

本文关键字:分配 对象 指针 何删除 删除      更新时间:2023-10-16

我是C++的新手,目前正在开发一款游戏。在游戏中,随着时间的推移,我会随机生成敌人,我使用std::vector来实现这一点。我想我可以用之类的东西

enemies.push_back(new Enemy(random_x, randomY));

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

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

您可以使用原始指针,如在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

如果您试图在位置3存储一个添加了属性的派生ExtraToughEnemy对象,比如说需要额外的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在堆上创建对象。

如果您在没有首先释放后备存储的情况下失去了对对象的访问权限,那么只有内存泄漏。这里的情况并非如此,因为您只需遍历enemies集合就可以调用find all these敌人。

大概在某个时候,你会从列表中删除敌人(例如,当你在游戏中杀死他们时)。在这一点上,你应该删除它们,内存将被回收。