以下C ++代码使用多个对象填充向量,然后删除其中一些对象,但看起来它删除了错误的对象:
vector<Photon> photons;
photons = source->emitPhotons(); // fills vector with 300 Photon objects
for (int i=0; i<photons.size(); i++) {
bool useless = false;
// process photon, set useless to true for some
// remove useless photons
if (useless) {
photons.erase(photons.begin()+i);
}
}
我这样做是否正确?我认为行photons.erase(photons.begin()+i);
可能是问题?
答案 0 :(得分:7)
绝对是错误的做法,你永远不会在删除时调整i
..
使用迭代器,这个问题就消失了!
e.g。
for(auto it = photons.begin(); it != photons.end();)
{
if (useless)
it = photons.erase(it);
else
++it;
}
还有其他方法可以使用算法(例如remove_if
和erase
等),但上面是最清楚的......
答案 1 :(得分:4)
优雅的方式是:
std::vector<Photon> photons = source->emitPhotons();
photons.erase(
std::remove_if(photons.begin(), photons.end(), isUseless),
photons.end());
和
bool isUseless(const Photon& photon) { /* whatever */ }
答案 2 :(得分:1)
正确的版本如下:
for (vector<Photon>::iterator i=photons.begin(); i!=photons.end(); /*note, how the advance of i is made below*/) {
bool useless = false;
// process photon, set useless to true for some
// remove useless photons
if (useless) {
i = photons.erase(i);
} else {
++i;
}
}
答案 3 :(得分:0)
在向量中间擦除元素效率非常低......其余元素需要“移位”回一个槽,以便填充由调用创建的向量中的“空”槽erase
。如果您需要擦除列表类型数据结构中间的元素而不会产生这样的惩罚,并且您不需要O(1)随机访问时间(即,您只是想将元素存储在你将在以后的其他地方复制或使用的列表,并且你总是遍历列表而不是随机访问它),你应该研究std::list
使用底层链表进行实现,给它O( 1)修改列表的复杂性,如插入/删除。
答案 4 :(得分:0)
在这种情况下,你应该使用stl :: list。引用STL文档:
列表具有重要的属性,即插入和拼接不会使列表元素的迭代器无效,甚至删除只会使指向被删除元素的迭代器无效。
所以这将是:
std::list<Photon> photons;
photons = source->emitPhotons();
std::list<Photon>::iterator i;
for(i=photons.begin();i!=photons.end();++i)
{
bool useless=false;
if(useless)
photons.erase(i);
}