为什么它需要它!= obj.end()虽然每个迭代器应该知道自己何时终止?

时间:2012-04-27 21:46:35

标签: c++ iterator containers

以下问题刚刚从头脑中射出。对于c ++ stl迭代器,通常的做法是使用类似的东西:

for (iterator it=obj.begin(); it!=obj.end(); it++)

我想知道的是,实际上obj.begin()可以告诉“它”何时停止哪个会使for循环看起来像:

for (iterator it=obj.begin(); !it.end(); it++)

好处是使迭代器更加自包含,并且可以在容器类中保存(迭代器end())。

7 个答案:

答案 0 :(得分:7)

有时候你想要做一些事情而不是遍历容器的整个内容。例如,您可以创建一对仅迭代容器前半部分的迭代器。因此,有一个单独的对象来表示结束是更灵活的,因为它允许用户更多地控制放置范围结束的位置。

你是对的,对于迭代所有内容的最常见情况来说,这有点不方便。但是,C ++ 11提供了一个基于for循环的范围,这使得在整个容器上循环变得非常容易,所以像编程中的许多东西一样,实际上只需要选择正确的结构来最好地表达你的意图。

答案 1 :(得分:4)

如果迭代器API的设计是这样的,那么指针就不会是一个有效的迭代器(因为一个指针显然不会有end())方法。因此,这将排除为具有连续内存的数据结构实现迭代器的最直接方式。

答案 2 :(得分:2)

有些图书馆提供的"java-style iterators"就像你描述的那样工作。

然而,这个方案(hasNext()等)的一个大问题是这样的迭代器是类。

例如,STL包含<algorithm>标头,其中包含std::copystd::generatestd::sortstd::lower_boundstd::fill等功能。这些例程使用开始/结束样式迭代器。因此,您可以使用具有这些功能的指针。如果这些函数在类的迭代器上运行(即如果它们在内部调用hasNext()而不是!= end()),那么你将无法将指针传递给std :: sort等。在这种情况下,您必须将所有内容都包装到类中,浪费您的时间,并且失去对<algorithm>的访问权限并不值得您通过向迭代器类添加atEnd()方法获得的方便。这可能是将迭代器与end()进行比较的原因。

答案 3 :(得分:1)

没有要求迭代器“了解”容器。它可以只知道并关心内存块或当前节点中的偏移(或任何适合于迭代的数据结构),而不知道包含容器的任何内容。例如,vector迭代器可以实现为一个简单的指针,而不知道(单独)向量结束的位置。

此外,STL算法也需要处理原始指针,因此迭代器需要“模仿”指针。

答案 4 :(得分:1)

最终它只是在STL发明时做出的决定(由Stepanov在90年代初期),后来在C ++标准化过程中得到批准,迭代器将是指针的泛化。来自http://www.sgi.com/tech/stl/stl_introduction.html

  

在反转C数组的示例中,反转的参数是   显然属于double*类型。如果你是的话,有什么反转的论据   但是,反转矢量,还是列表? ......答案就是   反转的参数是迭代器,它是泛化的   指针。

迭代器没有 是指针的泛化。理论上,C ++标准库(以及之前的STL)可以使用不同的迭代模型,其中迭代将由单个迭代器对象或单个范围对象表示,而不是由一对迭代器{{1 }和first

我认为不会有太大的性能差异。当然不会有现代C ++编译器。 STL(以及基于它的标准库)始终依赖于编译器对体面内联的性能,并且这些类不会比编译器在容器的内容中已经处理的更糟糕。提供一个将一对指针转换为迭代器或范围对象的简单包装器也不会有任何重大困难。

有些人确实更喜欢其他迭代器模型 - James Gosling(或者如果不是他,那么设计Java迭代器的人)。有些人更喜欢范围(包括大量的C ++程序员:因此Boost.Range)。

我怀疑STL和C ++的作者喜欢这样一个事实:STL样式的迭代器保留了与C的兼容性,你可以采用一种C算法,该算法使用指针来操作数组(或者由数组指定的其他范围)具有一对指针的用户),并将其几乎不变地转换为使用迭代器在容器(或其他范围)上操作的C ++算法。这种想法意味着你的新语言可以更容易被现有的用户群所吸收,这是C ++早期的目标之一。

所以类似的问题,“我们能否提供一种测试结束的方法,这种方法可以缩短几个字符,代价是使指针不再是迭代器并使迭代器更大”当时可能不会引起太多兴趣。但就在那时,例如Andrei Alexandrescu已经敲了一段时间,因为在他看来这不再是最好的选择了,并且这个范围比迭代器更好。

答案 5 :(得分:0)

让迭代器按照它的方式工作,可以灵活地处理子范围。您不必始终从begin()开始或以end()结束。例如,如果您想使用包含特定值的所有迭代器,则可以使用equal_range()的返回值作为开头和结尾。

D语言有range,它包含迭代器范围的开头和结尾。它也被提议用于C ++:http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/7e52451ed8eea31c

答案 6 :(得分:0)

知道迭代器的beginend(以及rbeginrend)的位置肯定是有用的,但是你说的情况在某种程度上由C ++ 11处理{ {3}}:

for (auto it: obj)
{
    // Do something with *it;
}

在没有编写太多锅炉板的情况下,在C ++ 11中完成工作要容易得多!