我正在编写一个使用大量包含指针的向量的程序,我担心删除指针的方式可能会导致内存泄漏。
例如,这是我向向量添加项目符号的方式:
Bullet* aNewBullet;
aNewBullet = new Bullet(x,y,dirX,dirY,size,duration);
aNewBullet->assignTexture(btext);
bulletVector.push_back(aNewBullet);
这就是我从向量中删除项目符号的方式(例如,如果它超出了它的范围)
int i=0;
while (i<bulletVector.size()){
if (bulletVector[i]->getDuration() ==0)
bulletVector.erase(bulletVector.begin() + i);
else i++;
}
我通过告诉矢量删除来删除项目符号吗? 还是我应该
int i=0;
while (i<bulletVector.size()){
if (bulletVector[i]->getDuration() ==0)
delete bulletVector[i];
bulletVector.erase(bulletVector.begin() + i);
else i++;
}
代替?通过首先删除指针,然后再次从向量中删除记录,这会弄乱向量的大小吗?
删除指针还会调用项目符号析构函数(〜Bullet())吗?
答案 0 :(得分:2)
在第一个代码示例中,您没有删除任何Bullet
对象。擦除vector
只会删除指针,而不会删除指向对象。
您的第二个示例确实删除了Bullet
(并非所有都具有条件和循环设置),但前提是您必须在修改矢量的所有点都进行了必要的删除,并手动确保了指针永远不会被删除两次(例如,因为它存在于两个向量中)。这不是应该使用容器的方式。
如果您确实要存储指针并拥有向量,那么您应该使用std::vector<std::unique_ptr<Bullet>>
,当删除向量时,它将正确删除Bullet
对象。但是矢量将变为不可复制(只能移动)。
但是,无论如何,如果向量都被认为拥有Bullet
,那么您可以直接将它们直接存储在向量中:std::vector<Bullet>
如果该向量不应该拥有Bullet
,则删除它们的责任在于实际拥有它们的任何对象,但是即使那样,仍需要做出一些努力来确保不保留已删除的指针在向量中。
答案 1 :(得分:1)
您需要delete
用new
创建的对象(除非您将指针移交给std::unique_ptr
或std::shared_ptr
)。考虑让向量成为对象的所有者。
std::vector<Bullet> bulletVector;
// in C++17, emplace_back returns a ref to the new Bullet:
Bullet& aNewBullet = bulletVector.emplace_back(x,y,dirX,dirY,size,duration);
// pre C++17:
bulletVector.emplace_back(x,y,dirX,dirY,size,duration);
Bullet& aNewBullet = bulletVector.back();
aNewBullet.assignTexture(btext);
现在您从向量中erase()
物体时,该物体将被自动破坏。
答案 2 :(得分:1)
首先,很可能通过不首先使用手动动态分配来解决您的问题。出于某些原因,您可以使用动态分配(例如,多态存储),但是即使那样,您也应该转向智能指针,而不是手动分配。
抛开指针
要使用规则的具体对象矢量(而不是指针)执行此操作,只需
std::vector<Bullet> bulletVector;
可以用类似的方法添加东西:
bulletVector.emplace_back(x,y,dirX,dirY,size,duration);
bulletVector.back().assignTexture(btext);
基于持续时间为零删除所有元素将仅使用remove/erase惯用法,如下所示:
bulletVector.erase(std::remove_if(
bulletVector.begin(),
bulletVector.end(),
[](auto const& b) { return b.getDuration() == 0; }),
bulletVector.end());
请记住,虽然这很容易成为存储这些内容的首选方法,但它需要更改其余代码。您目前在任何地方执行此操作:
bulletVector[i]->doSomething();
将成为
bulletVector[i].doSomething();
更多智能指针
如果必须使用动态分配,请不要使用手动管理的指针。它们是导致内存泄漏和所有权责任的良方,如果您认为这不可能发生在您身上,那您就太天真了。而是使用智能指针。两个主要的智能指针模板是std::unique_ptr
和std::shared_ptr
。还有std::weak_ptr
,值得一提,因为它在某些情况下非常方便(我可以告诉您的不是您的情况)。
std::vector<std::shared_ptr<Bullet>> bulletVector;
因此可以这样进行加法(假设这样做是出于多态性考虑,并且可能有不止一种项目符号类型,在这种情况下为MagicBullet
和SilverBullet
,两者均源自{{1 }}):
Bullet
或仅存储常规项目符号:
std::shared_ptr<Bullet> bullet = std::make_shared<MagicBullet>(x,y,dirX,dirY,size,duration);
bullet->assignTexture(btext);
bulletVector.emplace_back(bullet);
bullet = std::make_shared<SilverBullet>(x,y,dirX,dirY,size,duration);
bullet->assignTexture(btext);
bulletVector.emplace_back(bullet);
删除算法是相同的,只是条件谓词函数发生变化(并且变化不大)
bullet = std::make_shared<Bullet>(x,y,dirX,dirY,size,duration);
bullet->assignTexture(btext);
bulletVector.emplace_back(bullet);
最好的部分是代码的其余部分可能几乎不需要任何更改。但是我要强调的是,这是唯一的真正好处(除了显而易见的,即不再需要自己管理内存)。
给出两种方法之间的选择(具体对象的向量与智能指针的向量)进行仔细选择。如果前者有效,请使用它。如果没有,要么考虑它如何工作,要么使用后者。
但最重要的是,停止手动管理内存。
答案 3 :(得分:-1)
当然,您必须自己通过删除来删除项目符号。但是您的删除周期不正确。
要在某些情况下从向量中删除值,请使用类似以下内容的
:auto condFunc = [](const Bullet* x)
{
bool rez = (x->getDuration() == 0);
if(rez)
delete x;
return rez;
};
bulletVector.erase(std::remove_if(bulletVector.begin(), bulletVector.end(), condFunc), bulletVector.end());