与C ++迭代器混淆

时间:2015-07-23 01:25:22

标签: c++ pointers iterator

我有3个使用c ++迭代器的场景,这些场景让我很困惑。

这是我的主要代码:

int arr[] = {13,20,40};
set<int> st(arr,arr+3);

auto it=st.begin();
auto tmp=it;
it++;
st.erase(it);
//scenarios here

1-如果我写下面的内容,结果是20,为什么?

cout << *tmp << endl;

2-如果我向前移动指针,结果是13,为什么?

tmp++;
cout << *tmp << endl;

3-如果我向后移动指针,结果也是13,为什么它与向前移动相同?

tmp--;
cout << *tmp << endl;

4-最后,如果不是从集合中间删除某些东西,我会删除开始项目,结果是一个随机数。

auto it=st.begin();
auto tmp = it;
st.erase(it);

cout << *tmp << endl;//result: 13

tmp++;
cout << *tmp << endl;//result: random number

如果您知道有关此问题的c ++中有关迭代器的任何有用链接,请提及它们。

2 个答案:

答案 0 :(得分:2)

如果删除迭代器指向的set中的条目,则表明迭代器已失效。一旦迭代器失效,您就不应再使用它,因为它会导致未定义的行为。

答案 1 :(得分:0)

首先,您不要提及您的编译器。在像#34这样的问题中,我如何让C ++做X,Y和Z&#34;没关系,但在这样的问题中,你问为什么你的程序没有按照你的预期进行,你应该指定编译器(和版本!)。

原因很简单。首先,可能存在编译器错误,这可能导致某些代码无法执行它应该执行的操作。其次是标准的松散区域。例如,在这种情况下,没有提到如何实现集合,只是接口应该如何表现。所以set可以实现为树,数组,哈希表等等。这些行为改变了集合的行为,特别是&#34; undefined&#34;例。

第二,当你展示多个测试用例时,就像这里一样。将测试用例与宏分开会很有用。

#ifdef TEST1
   cout << *tmp << endl;
#endif
#ifdef TEST2
   tmp++;
   cout << *tmp << endl;
#endif
#ifdef TEST3
   tmp--;
   cout << *tmp << endl;
#endif

通常,您应该避免使用宏,但条件编译是该规则的少数例外之一。

现在谈谈你的问题。

首先。我倾向于使用大多数向量,我倾向于使用迭代器作为C样式指针和++和 - 作为指针算术。很难看出矢量的情况并非如此。但情况并非总是如此。这有点像我的直觉。尽管如此,这是一个很好的图片。

请记住,它只是最准确的。根据set的实现方式,迭代器将有所不同。在树的情况下,迭代器将是一个指针,++将是this->next并且 - 将是this->last

二。有两种类型的集合。集合(我将称之为基本集合)基于&#34;原始&#34;数据类型和虚拟集合,类似于目录列表或SQL结果集。在第一种情况下,几乎总有一个指针隐藏在迭代器的内部某处(或者不那么深)。即使在第二种情况下,也存在某种类似对象的指针(文件描述符/句柄,SQL游标)。因此,尽管迭代器处于未定义状态,它仍然会指向某个东西。虽然那件事可能无效。它就像一个指向错误位置的字符指针。那里还有角色,他们可能只是垃圾。

第三。要理解为什么迭代器在集合更改时变得不一致,请考虑在创建容器更改后保持一致的迭代器时必须执行的操作?首先,您需要在容器和迭代器中实现observer pattern,以便迭代器知道容器何时更改。迭代器应该是一个轻量级的对象。仅这一点就会导致迭代器大小加倍。传递消息会在创建迭代器时增加开销。

标准委员会有一条规则:任何您不使用的功能在不使用时都不应有开销。这意味着你需要单独的类至少一种方法来区分容器是否允许容器更改时一致的迭代器。这将意味着STL的额外复杂程度。

还有如何修复不一致迭代器的问题。假设删除了迭代器指向的元素。你是做什么?回去一个?前进一个?如果收集无序怎么办?然后更改集合可能会导致迭代顺序发生更改。你如何确保iteratior击中所有节点?

四。在做这样的事情(一个教学计划)时,用调试器逐步完成代码是个好主意,以了解内部发生了什么。

抱歉这花了这么久。但是我认为anwer比较复杂。这对C ++来说并不新鲜。欢迎来到。