集擦除表现得很奇怪

时间:2013-12-21 14:22:09

标签: c++ stl set

我刚刚编写了一些推送一些值的基本代码,通过使用指向它的迭代器(擦除)来删除一个值。该集合不包含该值,但迭代器仍指向已删除的值。

这不符合直觉吗?为什么会这样?

// erasing from set
#include <iostream>
#include <set>

int main ()
{
  std::set<int> myset;
  std::set<int>::iterator it;

  // insert some values:
  for (int i=1; i<10; i++) myset.insert(i*10);  // 10 20 30 40 50 60 70 80 90

  it = myset.begin();
  ++it;                                         // "it" points now to 20

  myset.erase (it);
  std::cout << *it << std::endl;                // still prints 20

  std::cout << "myset contains:";
  for (it=myset.begin(); it!=myset.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';
  return 0;
}

3 个答案:

答案 0 :(得分:3)

您的set迭代器无效。标准规定了取消引用无效集迭代器时所发生的事情的规则,因此behavior is undefined。允许返回20.就此而言,允许anything else

答案 1 :(得分:2)

  

该集合不包含该值,但迭代器仍指向已删除的值。

不,它没有。不是真的。

  

这不符合直觉吗?为什么会这样?

因为迭代器下面的内存仍然包含构成值20的位。这并不代表它的有效内存,或者那些位总是具有该值。

它只是一个幽灵。

答案 2 :(得分:1)

您从集合中删除了它,但迭代器仍然指向它在删除它之前指向的内存。除非擦除做了某些事情以使该存储器无效(例如,重新组织整个集合并对其进行写入),否则存储器及其内容仍然存在。

它已经“死了”。你不应该参考它。这是一个真正的问题......你不能迭代一个集合,在迭代器上调用“erase”,并期望迭代的内容仍然有效。据我所知,如果要使用它们删除集合的内容,则无法缓存迭代器并期望引用它们。

在迭代列表&lt;。&gt;时也是如此。迭代列表并使用迭代器擦除(。)某些元素很有诱惑力。但是erase(。)调用会破坏链接,因此迭代器不再有效。

当您遍历矢量&lt;。&gt;时也是如此。但那里更明显。如果我在元素N并对其进行调用擦除,则基础连续元素的大小会小1。

在一般情况下,它可能是为了避免虽然可以使用将在随后参考(例如循环的迭代器实现的底层容器(插入,擦除push_xxx等)的分配操作,解除引用操作之后是一个好主意等等。)。