简体   繁体   English

C++ (stl) 和 Java 中的迭代器,在概念上有区别吗?

[英]Iterators in C++ (stl) vs Java, is there a conceptual difference?

I'm returning to c++ after being away for a bit and trying to dust off the old melon.在离开了一段时间并试图清除旧瓜后,我将回到 C++。

In Java Iterator is an interface to a container having methods: hasNext() , next() and remove() .在 Java 中,迭代器是容器的接口,具有以下方法: hasNext()next()remove() The presence of hasNext() means it has the concept of a limit for the container being traversed. hasNext()的存在意味着它具有对正在遍历的容器的限制的概念

//with an Iterator
Iterator<String> iter = trees.iterator();
while (iter.hasNext()) 
{
    System.out.println(iter.next());
}

In the C++ standard template library, iterators seem to represent a datatype or class the supports the operator++ and operator== but has no concept of a limit built in so comparison is required before advancing to the next item.在 C++ 标准模板库中,迭代器似乎表示支持operator++operator==的数据类型或类,但没有内置限制的概念,因此在前进到下一项之前需要进行比较。 The limit has to checked by the user comparing two iterators in the normal case the second iterator is the container end.在正常情况下,用户必须通过比较两个迭代器来检查限制,第二个迭代器是容器端。

vector<int> vec;
vector<int>::iterator iter;

// Add some elements to vector
v.push_back(1);
v.push_back(4);
v.push_back(8);

for (iter= v.begin(); iter != v.end(); iter++)
{
    cout << *i << " "; //Should output 1 4 8
}

The interesting part here is that in C++ a pointer is an iterator to an array.有趣的是,在 C++ 中,指针是指向数组的迭代器。 The STL took what was existing and build convention around it. STL 采用了现有的内容并围绕它建立了约定。

It there any further subtlety to this that I am missing?我想念的还有什么更微妙的地方吗?

Perhaps a bit more theoretical.也许更理论化一点。 Mathematically, collections in C++ can be described as a half-open interval of iterators, namely one iterator pointing to the start of the collection and one iterator pointing just behind the last element.在数学上,C++ 中的集合可以描述为迭代器的半开区间,即一个迭代器指向集合的开头,一个迭代器指向最后一个元素的后面

This convention opens up a host of possibilities.这个约定开辟了许多可能性。 The way algorithms work in C++, they can all be applied to subsequences of a larger collection.算法在 C++ 中的工作方式,它们都可以应用于更大集合的子序列。 To make such a thing work in Java, you have to create a wrapper around an existing collection that returns a different iterator.要在 Java 中实现这样的功能,您必须围绕现有集合创建一个包装器,该集合返回不同的迭代器。

Another important aspect of iterators has already been mentioned by Frank. Frank 已经提到了迭代器的另一个重要方面。 There are different concepts of iterators.迭代器有不同的概念。 Java iterators correspond to C++' input iterators, ie they are read-only iterators that can only be incremented one step at a time and can't go backwards. Java迭代器对应于C++的输入迭代器,即只读迭代器,一次只能递增一步,不能倒退。

On the other extreme, you have C pointers which correspond exactly to C++' concept of a random access iterator.在另一个极端,您有 C 指针,它们与 C++ 的随机访问迭代器概念完全对应。

All in all, C++ offers a much richer and purer concept that can be applied to a much wider variety of tasks than either C pointers or Java iterators.总而言之,与 C 指针或 Java 迭代器相比,C++ 提供了更丰富、更纯粹的概念,可以应用于更广泛的任务。

Yes, there is a large conceptual difference.是的,存在很大的概念差异。 C++ utilizes different "classes" of iterators. C++ 使用不同的迭代器“类”。 Some are used for random access (unlike Java), some are used for forward access (like java).有些用于随机访问(与 Java 不同),有些用于前向访问(如 java)。 While even others are used for writing data (for use with, say, transform ).甚至其他人也用于写入数据(例如用于transform )。

See the iterators concept in the C++ Documentation :请参阅C++ 文档中的迭代器概念:

  • Input Iterator输入迭代器
  • Output Iterator输出迭代器
  • Forward Iterator前向迭代器
  • Bidirectional Iterator双向迭代器
  • Random Access Iterator随机访问迭代器

These are far more interesting and powerful compared to Java/C#'s puny iterators.与 Java/C# 的微不足道的迭代器相比,这些更有趣和强大。 Hopefully these conventions will be codified using C++0x's Concepts .希望这些约定将使用 C++0x 的Concepts进行编纂。

As mentioned, Java and C# iterators describe an intermixed position(state)-and-range(value), while C++ iterators separate the concepts of position and range.如前所述,Java 和 C# 迭代器描述了一个混合的位置(状态)和范围(值),而 C++ 迭代器将位置和范围的概念分开。 C++ iterators represent 'where am I now' separately from 'where can I go?'. C++ 迭代器分别代表“我现在在哪里”和“我可以去哪里?”。

Java and C# iterators can't be copied.无法复制 Java 和 C# 迭代器。 You can't recover a previous position.您无法恢复以前的位置。 The common C++ iterators can.常见的 C++ 迭代器可以。

Consider this example :考虑这个例子

// for each element in vec
for(iter a = vec.begin(); a != vec.end(); ++a){
  // critical step!  We will revisit 'a' later.
  iter cur = a; 
  unsigned i = 0;
  // print 3 elements
  for(; cur != vec.end() && i < 3; ++cur, ++i){
      cout << *cur << " ";
  }
  cout << "\n";
}

Click the above link to see program output.单击上面的链接查看程序输出。

This rather silly loop goes through a sequence (using forward iterator semantics only), printing each contiguous subsequence of 3 elements exactly once (and a couple shorter subsequences at the end).这个相当愚蠢的循环遍历一个序列(仅使用前向迭代器语义),打印 3 个元素的每个连续子序列一次(以及最后几个较短的子序列)。 But supposing N elements, and M elements per line instead of 3, this algorithm would still be O(N*M) iterator increments, and O(1) space.但是假设 N 个元素,每行 M 个元素而不是 3 个,这个算法仍然是 O(N*M) 迭代器增量和 O(1) 空间。

The Java style iterators lack the ability to store position independently. Java 风格的迭代器缺乏独立存储位置的能力。 You will either你要么

  • lose O(1) space, using (for example) an array of size M to store history as you iterate丢失 O(1) 空间,使用(例如)大小为 M 的数组在迭代时存储历史记录
  • will need to traverse the list N times, making O(N^2+N*M) time将需要遍历列表 N 次,使 O(N^2+N*M) 时间
  • or use a concrete Array type with GetAt member function, losing genericism and the ability to use linked list container types.或者使用具有 GetAt 成员函数的具体 Array 类型,失去通用性和使用链表容器类型的能力。

Since only forward iteration mechanics were used in this example, i was able to swap in a list with no problems .由于只有向前迭代机制,在此例子中,我能交换与名单没有问题 This is critical to authoring generic algorithms, such as search, delayed initialization and evaluation, sorting, etc.这对于编写通用算法至关重要,例如搜索、延迟初始化和评估、排序等。

The inability to retain state corresponds most closely to the C++ STL input iterator, on which very few algorithms are built.无法保持状态最接近于 C++ STL 输入迭代器,在其上构建的算法很少。

A pointer to an array element is indeed an iterator into the array.指向数组元素的指针实际上是数组的迭代器。

As you say, in Java, an iterator has more knowledge of the underlying container than in C++.正如您所说,在 Java 中,迭代器比 C++ 对底层容器有更多的了解。 C++ iterators are general, and a pair of iterators can denote any range: this can be a sub-range of a container, a range over multiple containers (see http://www.justsoftwaresolutions.co.uk/articles/pair_iterators.pdf or http://www.boost.org/doc/libs/1_36_0/libs/iterator/doc/zip_iterator.html ) or even a range of numbers (see http://www.boost.org/doc/libs/1_36_0/libs/iterator/doc/counting_iterator.html ) C++ 迭代器是通用的,一迭代器可以表示任何范围:这可以是一个容器的子范围,一个跨多个容器的范围(参见http://www.justsoftwaresolutions.co.uk/articles/pair_iterators.pdfhttp://www.boost.org/doc/libs/1_36_0/libs/iterator/doc/zip_iterator.html )甚至一系列数字(参见http://www.boost.org/doc/libs/1_36_0 /libs/iterator/doc/counting_iterator.html )

The iterator categories identify what you can and can't do with a given iterator.迭代器类别标识您可以使用给定的迭代器做什么和不能做什么。

对我来说,根本的区别在于 Java 迭代器指向项之间,而 C++ STL 迭代器指向项。

There are plenty of good answers about the differences, but I felt the thing that annoys me the most with Java iterators wasn't emphasized--You can't read the current value multiple times.关于差异有很多很好的答案,但我觉得 Java 迭代器最让我烦恼的事情没有被强调——你不能多次读取当前值。 This is really useful in a lot of scenarios, especially when you are merging iterators.这在很多场景中非常有用,尤其是在合并迭代器时。

In c++, you have a method to advance the iterator and to read the current value.在 C++ 中,您有一个方法来推进迭代器并读取当前值。 Reading its value doesn't advance the iteration;读取它的值不会推进迭代; so you can read it multiple times.所以你可以多次阅读它。 This is not possible with Java iterators, and I end up creating wrappers that do this.这对于 Java 迭代器是不可能的,我最终创建了执行此操作的包装器。

A side note: one easy way to create a wrapper is to use an existing one-- PeekingIterator from Guava.旁注:创建包装器的一种简单方法是使用现有的包装器——来自 Guava 的PeekingIterator

C++ iterators are a generalization of the pointer concept; C++ 迭代器是指针概念的概括; they make it applicable to a wider range of situations.它们使其适用于更广泛的情况。 It means that they can be used to do such things as define arbitrary ranges.这意味着它们可以用来做诸如定义任意范围之类的事情。

Java iterators are relatively dumb enumerators (though not so bad as C#'s; at least Java has ListIterator and can be used to mutate the collection). Java 迭代器是相对愚蠢的枚举器(虽然不像 C# 那样糟糕;至少 Java 有 ListIterator 并且可以用来改变集合)。

Iterators are only equivalent to pointers in the trivial case of iterating over the contents of an array in sequence.在按顺序迭代数组内容的平凡情况下,迭代器仅等效于指针。 An iterator could be supplying objects from any number of other sources: from a database, from a file, from the network, from some other calculation, etc.迭代器可以从任意数量的其他来源提供对象:来自数据库、文件、网络、其他一些计算等。

C++ library (the part formerly known as STL) iterators are designed to be compatible with pointers. C++ 库(以前称为 STL 的部分)迭代器旨在与指针兼容。 Java, without pointer arithmetic, had the freedom to be more programmer-friendly. Java,没有指针算法,可以自由地对程序员更友好。

In C++ you end up having to use a pair of iterators.在 C++ 中,您最终不得不使用一对迭代器。 In Java you either use an iterator or a collection.在 Java 中,您可以使用迭代器或集合。 Iterators are supposed to be the glue between algorithm and data structure.迭代器应该是算法和数据结构之间的粘合剂。 Code written for 1.5+ rarely need mention iterators, unless it is implementing a particular algorithm or data structure (which the vary majority of programmers have no need to do).为 1.5+ 编写的代码很少需要提及迭代器,除非它正在实现特定的算法或数据结构(大多数程序员不需要这样做)。 As Java goes for dynamic polymorphism subsets and the like are much easier to handle.由于 Java 使用动态多态性子集等,因此更容易处理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM