矢量擦除迭代器

我有这个密码:

int main()
{
vector<int> res;
res.push_back(1);
vector<int>::iterator it = res.begin();
for( ; it != res.end(); it++)
{
it = res.erase(it);
//if(it == res.end())
//  return 0;
}
}

一个随机访问迭代器,指向被函数调用擦除的最后一个元素后面的元素的新位置,如果操作擦除了序列中的最后一个元素,则指向向量结束

这段代码崩溃了,但是如果我使用 if(it == res.end())部分,然后返回,它就可以工作了。为什么?For 循环是否缓存 res.end()以使不相等运算符失败?

157468 次浏览

res.erase(it)总是返回下一个有效的迭代器,如果擦除最后一个元素,它将指向 .end()

在循环的末尾总是调用 ++it,所以增加 .end()是不允许的。

但是,简单地检查 .end()仍然会留下一个 bug,因为您总是在每次迭代中跳过一个元素(it通过 .erase()返回“增加”,然后通过循环再次“增加”)

你可能想要这样的东西:

 while (it != res.end()) {
it = res.erase(it);
}

清除每一个元素

(为了完整起见: 我假设这是一个简化的例子,如果您只是希望删除每个元素,而不需要对其执行操作(例如 delete) ,那么您应该简单地调用 res.clear())

如果只有条件地删除元素,那么可能需要

for ( ; it != res.end(); ) {
if (condition) {
it = res.erase(it);
} else {
++it;
}
}

不要擦除然后增加迭代器。不需要增量,如果你的向量有一个奇数(或偶数,我不知道)的元素,你会错过向量的结束。

It + + 指令在块的末尾执行。因此,如果要擦除最后一个元素,那么尝试增加指向空集合的迭代器。

在 for 循环的循环表达式中,在(空)容器的末尾递增 it

for( ; it != res.end();)
{
it = res.erase(it);
}

或者,更笼统地说:

for( ; it != res.end();)
{
if (smth)
it = res.erase(it);
else
++it;
}

下列措施似乎也有效:

for (vector<int>::iterator it = res.begin(); it != res.end(); it++)
{
res.erase(it--);
}

不知道这里面有没有漏洞?

if(allPlayers.empty() == false) {
for(int i = allPlayers.size() - 1; i >= 0; i--)
{
if(allPlayers.at(i).getpMoney() <= 0)
allPlayers.erase(allPlayers.at(i));
}
}

这对我很有用,不用考虑索引已经被删除了。

作为对疯狂拉默尔答案的修正,我经常使用:

your_vector_type::iterator it;
for( it = res.start(); it != res.end();)
{
your_vector_type::iterator curr = it++;
if (something)
res.erase(curr);
}

这样做的好处是,您不必担心忘记增加迭代器,这样当您有复杂的逻辑时,迭代器就不容易出错。在循环内部,curr 永远不会等于 res.end () ,并且不管是否从向量中删除它,它都将位于下一个元素。

因为向量中的方法擦除返回传递的迭代器的下一个迭代器。

我将举例说明如何在迭代时删除矢量中的元素。

void test_del_vector(){
std::vector<int> vecInt{0, 1, 2, 3, 4, 5};


//method 1
for(auto it = vecInt.begin();it != vecInt.end();){
if(*it % 2){// remove all the odds
it = vecInt.erase(it); // note it will = next(it) after erase
} else{
++it;
}
}


// output all the remaining elements
for(auto const& it:vecInt)std::cout<<it;
std::cout<<std::endl;


// recreate vecInt, and use method 2
vecInt = {0, 1, 2, 3, 4, 5};
//method 2
for(auto it=std::begin(vecInt);it!=std::end(vecInt);){
if (*it % 2){
it = vecInt.erase(it);
}else{
++it;
}
}


// output all the remaining elements
for(auto const& it:vecInt)std::cout<<it;
std::cout<<std::endl;


// recreate vecInt, and use method 3
vecInt = {0, 1, 2, 3, 4, 5};
//method 3
vecInt.erase(std::remove_if(vecInt.begin(), vecInt.end(),
[](const int a){return a % 2;}),
vecInt.end());


// output all the remaining elements
for(auto const& it:vecInt)std::cout<<it;
std::cout<<std::endl;


}

产出如下:

024
024
024

更多的生成方法:

template<class Container, class F>
void erase_where(Container& c, F&& f)
{
c.erase(std::remove_if(c.begin(), c.end(),std::forward<F>(f)),
c.end());
}


void test_del_vector(){
std::vector<int> vecInt{0, 1, 2, 3, 4, 5};
//method 4
auto is_odd = [](int x){return x % 2;};
erase_where(vecInt, is_odd);


// output all the remaining elements
for(auto const& it:vecInt)std::cout<<it;
std::cout<<std::endl;
}

使用现代 C + + 可以使用“ std: : remove _ if”和 lambda 表达式;

此代码将删除向量的“3”

vector<int> vec {1,2,3,4,5,6};


vec.erase(std::remove_if(begin(vec),end(vec),[](int elem){return (elem == 3);}), end(vec));