与下面的代码一样,m_vSprites是shred_ptr的向量,如果他的一个元素更新失败,我想从向量中删除它,但是当我想使用erase时我的代码崩溃了。但我不知道为什么,任何人都可以提供帮助?
我需要使用erase的原因是因为我的应用程序会不断地在向量中添加元素,但如果某些元素满足其杀死条件,它还会不断地从向量中擦除对象。如果我没有删除它,那么当程序运行时,向量会变得很大!
RECT rcOldSpritePos;
typedef boost::shared_ptr<Sprite> SmartSprite;
vector<SmartSprite>::iterator siSprite;
for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end();)
{
// Save the old sprite position in case we need to restore it
rcOldSpritePos = (*siSprite)->getPosition();
if (!((*siSprite)->update()))
{
// Kill the sprite
//siPreviousSprite = siSprite-1;
siSprite = m_vSprites.erase(siSprite);
}
else
{
siSprite++;
// See if the sprite collided with any others
if (checkSpriteCollision(*siSprite))
// Restore the old sprite position
(*siSprite)->setPosition(rcOldSpritePos.left, rcOldSpritePos.top);
}
}
我已根据有人的建议更改了代码,但在删除功能中仍然失败,请问有人有什么建议吗?
有关如何在vecotr中添加元素的更多信息
这里有问题吗?
SmartSprite sprite;
if (0 < enemies.size())
{
// Pick a random enemy to drop bomb
size_t nRandEnemy = (rand() % enemies.size());
RECT rRandEnemy = enemies.at(nRandEnemy)->getPosition();
sprite.reset(new BombSprite(m_system, rRandEnemy.right-OBJECTSIZE/2,
rRandEnemy.bottom));
m_vSprites.push_back(sprite);
}
我的sprite类没有任何析构函数......
另外一个信息是,当我调试时,发现它崩溃了 擦除内部函数:_Destroy(_Mylast - 1,_Mylast);
问题解决了!原因是在我的Sprite类中,我将其包装为智能指针,并创建另一个智能指针作为其成员变量。现在我没有使用智能指针成员变量,系统没有再次崩溃....我将继续思考为什么我不能在该类中使用智能指针,当从向量中擦除精灵时,它的成员变量有关系吗?如果只使用原始指针而不是起诉智能指针,我还需要删除该成员变量吗?
答案 0 :(得分:5)
如果你要擦除的迭代器是向量的开始迭代器,那么这个;
siPreviousSprite = siSprite - 1;
是未定义的行为。像这样重构你的循环:
for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); )
{
rcOldSpritePos = (*siSprite)->getPosition();
if (!((*siSprite)->update()))
{
// Kill the sprite
siSprite = m_vSprites.erase(siSprite);
}
else
{
++siSprite;
}
}
如果仍有崩溃,那么你的精灵类一定有问题。
答案 1 :(得分:3)
如果siSprite == m_vSprites.begin()
则siSprite-1
不合法。编写这种循环的通常方法是
for (siSprite = m_vSprites.begin(); siSprite != m_vSprites.end(); )
{
rcOldSpritePos = (*siSprite)->getPosition();
if ((*siSprite)->update())
{
++siSprite;
}
else
{
siSprite = m_vSprites.erase(siSprite);
}
}
不确定这是否会真正解决您的问题,因为您的错误可能是完全无关的。
答案 2 :(得分:3)
我尝试使用erase-remove idiom。
您可能希望从sprite类公开bool
属性,并检查是否true
从向量中删除sprite。
像这样(用VC10 / VS2010 SP1测试的代码):
#include <algorithm>
#include <iostream>
#include <memory>
#include <ostream>
#include <vector>
using namespace std;
struct Sprite
{
explicit Sprite(int spriteId)
: kill(false)
, id(spriteId)
{
}
int id;
bool kill;
};
int main()
{
typedef shared_ptr<Sprite> SmartSprite;
typedef vector<SmartSprite> SpriteArray;
SpriteArray sprites;
for (int i = 0; i < 5; i++)
sprites.push_back( make_shared<Sprite>(i*11) );
for (auto it = sprites.begin(); it != sprites.end(); ++it)
cout << (*it)->id << " ";
cout << endl;
sprites[2]->kill = true;
sprites[3]->kill = true;
// Remove sprites with kill flag set
sprites.erase
(
remove_if
(
sprites.begin(),
sprites.end(),
[](const SmartSprite& ps){ return ps->kill; }
),
sprites.end()
);
for (auto it = sprites.begin(); it != sprites.end(); ++it)
cout << (*it)->id << " ";
cout << endl;
}
输出:
0 11 22 33 44
0 11 44
答案 3 :(得分:1)
擦除可能会导致新的分配,迭代器可能会在那里中断。最好这样做:
for(size_t i=0; i<v.size(); ++i)
if(!v[i].update())
{
v.erase(v.begin()+i);
--i; // since the elements shifted up.
}
否则你可能想要使用队列,在矢量上擦除操作非常昂贵。
编辑:
我使用虚拟Sprite类测试它并且工作正常,错误必须在Sprite类的析构函数内。