【问题标题】:set erase behaves weird设置擦除行为很奇怪
【发布时间】:2013-12-21 14:22:08
【问题描述】:

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

这不是违反直觉吗?为什么会这样?

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

【问题讨论】:

    标签: c++ stl set


    【解决方案1】:

    您的集合迭代器无效。该标准没有规定当您取消引用无效集合迭代器时会发生什么规则,因此behavior is undefined。允许返回 20。允许这样做anything else。

    【讨论】:

      【解决方案2】:

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

      不,它没有。不是真的。

      这不是违反直觉吗?为什么会这样?

      因为迭代器下面的内存仍然恰好包含构成值20 的位。这并不意味着它是有效内存,或者这些位将始终具有该值。

      只是个鬼。

      【讨论】:

        【解决方案3】:

        你从集合中删除了它,但迭代器仍然指向它在你删除它之前指向的内存。除非擦除操作使该内存无效(例如,重新组织整个集合并覆盖它),否则内存及其内容仍然存在。

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

        迭代列表时也是如此<.>。迭代列表并使用迭代器擦除(。)某些元素是很诱人的。但是 erase(.) 调用会破坏链接,因此您的迭代器不再有效。

        当你迭代一个向量时也是如此<.>。但那里更明显。如果我在元素 N 上并对其调用擦除,则底层连续元素的大小会小 1。

        一般来说,避免可能影响底层容器分配的操作(insert、erase、push_xxx 等)可能是一个好主意,同时使用随后将被引用的迭代器(例如循环、操作后取消引用)等)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-08-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-09-30
          • 1970-01-01
          • 1970-01-01
          • 2018-10-23
          相关资源
          最近更新 更多