4

以下问题刚刚在我脑海中闪过。对于 c++ stl 迭代器,一种常见的做法是使用以下内容:

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

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

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

好处是使迭代器更加独立,并且可以将 (iterator end()) 保存在容器类中。

4

7 回答 7

7

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

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

于 2012-04-27T21:56:42.907 回答
4

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

于 2012-04-27T21:53:06.590 回答
2

一些库提供像您描述的那样工作的“java 风格的迭代器” 。

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

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

于 2012-04-27T22:04:32.363 回答
1

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

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

于 2012-04-27T21:54:54.207 回答
1

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

在反转 C 数组的示例中,要反转的参数显然是double*. 但是,如果要反转向量或列表,要反转的参数是什么?...答案是 reverse 的参数是迭代器,它是指针的泛化。

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

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

有些人确实更喜欢其他迭代器模型——James Gosling 就是其中之一(或者如果不是他,也就是设计 Java 迭代器的人)。有些人更喜欢范围(包括很多 C++ 程序员:因此是 Boost.Range)。

I suspect the authors of the STL and C++ liked the fact that STL-style iterators retained a kind of compatibility with C, that you could take a C algorithm that used pointers to operate on an array (or other range specified by the user with a pair of pointers), and transform it almost unchanged into a C++ algorithm that uses iterators to operate on a container (or other range). That's the kind of thinking that means your new language can be more easily assimilated by an existing user-base, which was one of the goals of C++ early on.

So questions like, "can we provide a means of testing for end which is a few characters shorter, at the cost of making pointers no longer be iterators and making iterators larger" probably would not have got much interest at the time. But that was then, and for example Andrei Alexandrescu has been banging on for a while now that in his opinion this is not longer the best choice, and that ranges are better than iterators.

于 2012-04-28T00:01:15.757 回答
0

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

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

于 2012-04-27T21:55:28.633 回答
0

知道迭代器的beginand end(和rbeginand rend)在哪里当然很有用,但是您所说的情况在某种程度上由 C++11 的基于范围的for-loop处理:

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

在 C++11 中完成工作要容易得多,而无需编写如此多的样板!

于 2012-04-27T22:52:59.013 回答