擦除元素时std :: vector中可能存在的不一致

时间:2013-04-12 14:18:47

标签: c++ vector

在调试向量时,我发现不一致。假设以下代码尝试从只有一个元素的向量中删除条目

#include <iostream>
#include <vector>
std::vector<int> v;
void myremove(int);
int main()
{
  v.push_back(10); 
  std::cout << "10 pushed back\n";
  myremove(10);
  std::cout << "done :)\n";
  return 0;
}

void myremove( int a )
{
  std::vector<int>::iterator it = v.begin();
  int counter = 0;
  for ( ; it != v.end(); it++ ) {
    std::cout << "iterating for " << counter << " times and vector size is " << v.size() << "\n";
    if ( a == (*it) ) {
      v.erase(it);
      std::cout << "removed " << a << "\n";
    }
    ++counter; 
  }
}

这是我在输出中看到的:

 $ g++ test.cpp 
 $ ./a.out | more
 10 pushed back
 iterating for 0 times and vector size is 1
 removed 10
 iterating for 1 times and vector size is 0
 iterating for 2 times and vector size is 0
 iterating for 3 times and vector size is 0
 iterating for 4 times and vector size is 0
 iterating for 5 times and vector size is 0
 iterating for 6 times and vector size is 0
 ....
 ....
 iterating for 33790 times and vector size is 0
 Segmentation fault

我理解的是,当元素被移除时,大小将变为0,但迭代器移动一步仍然会尝试到达终点,但他不知道他已经通过了终点。

有人可以解释发生了什么以及如何避免这种情况吗?

6 个答案:

答案 0 :(得分:6)

调用erase()后,迭代器it无效:

  

对擦除元素以及它们与容器末尾之间元素的迭代器和引用无效。

it设置为erase()的返回值,只有在没有删除时才会递增:

while (it != v.end())
{
    if ( a == (*it) )
    {
        it = v.erase(it);
        std::cout << "removed " << a << "\n";
    }
    else
    {
        ++it;
    }
}

erase()的返回值为:

  

最后一个删除元素之后的迭代器。

而不是手动编码循环来擦除元素,而不是使用std::remove_if()

v.erase(std::remove_if(v.begin(),
                       v.end(),
                       [](const int i) { return i == 10; }),
        v.end());

答案 1 :(得分:4)

擦除时

v.erase(it);

你的迭代器不再有效了。您必须使用擦除返回的迭代器。擦除为您提供一个迭代器,指向调用擦除元素后面的元素。如果你在循环增加it 之前删除了最后一个元素,那么你必须打破循环。

it = v.erase(it);
if(it == v.end())
    break;

建议:您可以继续将for循环更改为while循环。并明确地增加迭代器(即只有当你没有删除任何东西时。如果你已经删除了迭代器,那么已经增加了)。

喜欢这个

while(it != v.end()) {
    if ( a == (*it) ) 
      it = v.erase(it);
    else
      ++it; 
}

答案 2 :(得分:0)

每次插入和擦除都会使容器的所有迭代器无效。插入/擦除后,这些方法返回ONLY有效的迭代器。

答案 3 :(得分:0)

答案 4 :(得分:0)

当你调用erase函数时,迭代器不再是有效的迭代器,当你增加无效迭代器时,你会得到虚假的结果。

答案 5 :(得分:0)

错误在于,在对迭代器进行擦除之后,您希望此迭代器仍处于一致状态。情况并非如此,您的代码会准确说明发生这种情况时的情况。

你的函数的语义是删除向量的所有元素等于a。您可以通过过滤矢量来获得相同的结果。请看这个问题:

How to make std::vector from other vector with specific filter?