如果已删除,如何从向量中删除对象
Posted
技术标签:
【中文标题】如果已删除,如何从向量中删除对象【英文标题】:How to remove object from a vector if it was deleted 【发布时间】:2021-04-09 11:55:16 【问题描述】:我正在制作一个玩家可以射击的主机游戏。玩家按下空格键后,会创建一个新对象并将其放置在地图上,并且地图包含指向该对象的指针。这些对象存储在向量中。我读了一篇关于向量的文章,上面写着:
向量与动态数组相同,可以在插入或删除元素时自动调整大小
我以为我删除一个物体后,矢量会自动缩小,所以每当其中一个弹丸撞到墙上时我就这样做了:
delete entities[x + y * width];
entities[x + y * width] = nullptr;
但是向量的大小没有改变。我需要从向量中手动删除对象吗?我有一个想法,为每个存储其状态(死/活)的弹丸创建一个布尔变量,以便在循环的帮助下手动将其从向量中删除。有更好的方法吗?
另外,将射弹存储在矢量中是否安全?我读到该向量将在达到最大大小时将自身复制到内存的另一段。之后我的地图中的指针会发生什么?
代码如下所示:
#include <vector>
#include <iostream>
#include <conio.h>
class Entity
public:
int x, y;
int getX() return x;
int getY() return y;
;
class Projectile : public Entity
public:
Projectile(int x, int y)
this->x = x;
this->y = y;
;
class Map
public:
Entity** entities;
int width, height;
Map(int width, int height)
this->width = width;
this->height = height;
void spawn(Entity* entity)
entities[entity->getX() + entity->getY() * width] = entity;
;
int main()
Map map(10, 10);
std::vector<Projectile*> projectiles;
map.entities = new Entity* [map.width * map.height];
int x, y;
while (true)
if (_getch() == 32)
std::cin >> x >> y;
projectiles.push_back(new Projectile(x, y));
map.spawn(*projectiles.begin());
//...
bool hitWall = true;
if (hitWall)
delete map.entities[x + y * map.width];
map.entities[x + y * map.width] = nullptr;
return 0;
【问题讨论】:
在向量中存储指向射弹的原始拥有指针可能不安全。如果您要存储对象,您只需调用entities.erase(...)
。你能显示minimal reproducible example吗?
@largest_prime_is_463035818 我添加了代码。
在您的代码中 entities
不是向量。如果你写了std::vector<Entity*> entities;
(存储指针的警告适用,请参阅 cmets 和答案)
@spectras 游戏中的所有实体(敌人/玩家等)都存储在数组entities
中,但射弹在向量中:std::vector<Projectile*> projectiles;
@kastrycznik 仅供参考——Entity
缺少虚拟析构函数,因此您现在通过基类指针的实体 delete
是未定义的行为。第二件事是,除非您是一名高级 C++ 程序员,知道他们需要了解的有关指针和动态内存管理的所有知识,并且有充分的理由编写此类代码,否则Entity** entities;
是一种代码味道。
【参考方案1】:
根据您的示例代码,我假设您的向量定义如下:
std::vector<YourType*> entities;
因此,您的向量不包含YourType
对象,而是pointer to YourType
。也就是说,向量管理的元素是指针,而不是指向的对象。
因此,当您这样做 delete entities[x + y * width];
时,您确实删除了 YourType
实例,但指针仍然存在并且它仍然存在于您的向量中。
如果您将该语句分解为等效的 2 行,可能会更容易可视化:
YourType * pointer = entities[x + y * width];
delete pointer;
要真正从向量中移除指针,你需要这样说:
entities.erase(entities.begin() + x + y * width);
这将从数组中删除指针(也将所有内容移出该索引)。您仍然需要自己执行delete
,因为向量只管理指针,而不是YourType
。
请注意,除非您有充分的理由,否则您可能不应将指针存储在向量中,而应将对象本身存储。这将消除您的困惑:
std::vector<YourType> entities;
// deleting a YourType:
entities.erase(entities.begin() + x + y * width);
不再有delete
或new
,因为对象直接在向量中。所以向量会为你管理它,而不是仅仅管理指针并让你处理指向的对象。
问题编辑后更新:
在您的情况下,您确实有充分的理由,因为您实际上存储了一个非拥有指针。因此entities
和projectiles
存储指针可能是有意义的,因此它们实际上指向相同的对象。
所以两个向量都会管理它们的指针,但是你必须考虑这两个指针(一个来自实体,一个来自射弹)的生命周期如何与对象本身交互。
删除对象不会删除指针,在两个数组中都没有。
【讨论】:
【参考方案2】:您需要使用迭代器。像这样:
entities.erase(entities.begin() + x + y * width)
关于安全性,对于经常实例化和销毁的小对象,最好直接存储对象而不是指针。这消除了堆分配带来的内存泄漏或悬空指针的可能性。
【讨论】:
以上是关于如果已删除,如何从向量中删除对象的主要内容,如果未能解决你的问题,请参考以下文章