矢量擦除迭代器

时间:2011-01-10 10:22:04

标签: c++ vector iterator

我有这段代码:

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()以使不相等的运算符失败?

10 个答案:

答案 0 :(得分:132)

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

在循环结束时始终会调用++it,因此您需要增加.end(),这是不允许的。

简单地检查.end()仍然会留下一个错误,因为你总是在每次迭代时跳过一个元素(it.erase()返回'递增',然后再通过循环)

您可能需要以下内容:

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

删除每个元素

(为了完整性:我假设这是一个简化的例子,如果你只是希望每个元素都消失而不必对它进行操作(例如删除),你只需要调用res.clear()

当你只是有条件地擦除元素时,你可能需要像

这样的东西
for ( ; it != res.end(); ) {
  if (condition) {
    it = res.erase(it);
  } else {
    ++it;
  }
}

答案 1 :(得分:27)

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

或者,更一般:

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

答案 2 :(得分:1)

作为对madlammer答案的修改,我经常使用:

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(),并且无论是否从向量中删除它,它都将位于下一个元素。

答案 3 :(得分:1)

您可以使用现代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));

答案 4 :(得分:0)

不要擦除然后递增迭代器。不需要增加,如果你的向量有一个奇数(或者甚至,我不知道)的元素数量,你将错过向量的末尾。

答案 5 :(得分:0)

it ++指令在块结束时完成。因此,如果您正在擦除最后一个元素,那么您尝试增加指向空集合的迭代器。

答案 6 :(得分:0)

在for循环的循环表达式中,将it增加到(空)容器的末尾。

答案 7 :(得分:0)

以下似乎也有效:

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

不确定这是否有任何缺陷?

答案 8 :(得分:0)

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

这对我有用。并且不需要考虑索引已经删除。

答案 9 :(得分:0)

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

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

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;

}

在下面输出aw

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;    
}