一般而言,什么是迭代器?

时间:2018-07-30 03:08:01

标签: c++ iterator

当我尝试用ctor编写一个接受“通用迭代器”的C ++类模板时,会出现此问题。我不知道在这里使用 general 一词是否合适,但我的意思是它可以像STL容器一样接受迭代器。

换句话说,我对迭代器感到困惑。似乎所有STL容器都具有相同的类型迭代器,那是什么类型?只是指针吗?还是更复杂的东西?但是STL容器确实接受普通指针。

(我想将其与Iterator<T>中的Java进行比较,这很简单,它只是一个类)

3 个答案:

答案 0 :(得分:37)

在C ++中,迭代器是一种概念,不是具体的(或抽象的)类型,而是任何服从某些的类型。像规则这样的迭代器。

例如,迭代器通常可以递增git。可以访问(取消引用)++i以获取它们当前指向的值。它们本质上是指针的抽象。

在标准库的容器和算法中,有各种具有不同属性的迭代器。它们的属性在这里列出:

https://en.cppreference.com/w/cpp/iterator

因此,在用C ++编写接受迭代器的算法时,通常只接受 generic 模板参数,并在函数中使用适当的迭代器属性。如果用户向您的函数传递了不遵守迭代器规则的内容,则编译器会抱怨:

*i

您可以添加大量特定检查,以确保用户通过了明智的选择,但这对于这个问题来说太宽泛了。

注意:

目前,诸如Iterator之类的概念只是程序员必须遵循的标准中的一组商定的语义属性,而更全面的解决方案将使 formalize < / em>这样的概念(以代码形式)适用于标准的下一版本C++20

答案 1 :(得分:6)

迭代器作为概念来自C ++成为标准之前。

C ++最初是带有类的C语言。添加了更多功能,并且对这种语言的兴趣呈指数增长。

一项非常重要的工作称为STL-标准模板库-最初由Stepanov和Lee编写。于1994年在惠普公司任职,后来由SGI维护。

该库以颇具革命性的方式使用了C ++的模板元编程部分。编写该文件是为了允许对几乎任意类型的抽象类型使用接近裸机的性能,而将算法实现与容器实现分离开来。

迭代器是一个概念-一种更高的类型

在其中,迭代器是一个概念。 C ++中的概念是类型的类别(可以说是一种类型的类型)。 (目前)编译器不强制使用C ++中的概念。

如果类型具有必需的操作,并且该操作符合该概念的规则,则它可以满足该概念。

在STL和更高版本的C ++标准中,围绕迭代器的概念有很多层次。它们从限制最小的(迭代器)到限制最大的(读写随机访问连续迭代器),并形成一棵树。

模板函数编写函数

当模板算法要求提供Iterator时,他们要求的是满足Iterator概念的类型(如C ++标准中所述)。当他们要求使用RandomAccessIterator时,他们要求的是一种可以满足RandomAccessIterator概念(还包括Iterator概念,ForwardIterator概念以及其他一些概念)的类型。

所以template<class ForwardIterator> void std::sort( ForwardIterator, ForwardIterator )是一个模板函数,它接受两个满足ForwardIterator概念的相同类型的实例。

ForwardIterator必须支持多种操作(*it++itbool b = it != itbool b = it == it等),支持某些特征(iterator_traits<it>::iterator_category,{ {1}},iterator_traits<it>::reference等),并且这些操作必须遵循某些规则。

如果您将其提供的类型满足RandomAccessIterator,则iterator_traits<it>::value_type会比传递std::sort时保证更好的性能。

原始指针可以满足两个Forward RandomAccess迭代器,而无需您进行任何操作。 ForwardIterator也满足了这两个条件,但通常不是原始指针(std库做了一些工作)。

这两种类型-原始指针和std::vector<?>::iterator-通常是不相关的类型。 C ++的模板和特征系统允许使用相同的模板算法来理解无关类型,而运行时开销为零。

中,有计划引入语言内概念,这些概念实际上检查诸如RandomAccessIterator之类的某些要求,并记录语言内实际上无法检查的其他要求。

C ++不是OO语言

您可能习惯于使用面向对象的语言而感到困惑。 C ++支持面向对象的编程,但不是面向对象的语言。它支持多态-相同地对待多种类型-无需通过多种方式实现基于对象的继承。

在面向对象的语言中,每个迭代器都将从抽象的迭代器类型继承。算法将通过该抽象接口与迭代器进行交互,通常通过某种虚拟函数表调度调用。该类型的值是不可能的,因为将在不知道迭代器占用多少字节的情况下编译算法代码,因此会发生额外的间接访问。

在C ++中,直到您将其传递给迭代器的类型,该算法才是函数。此时,该函数是为该迭代器自定义编写的。 C ++标准规定,如果迭代器执行某些操作(遵循必需的概念),则模板编写的函数将具有某些行为。

此模板编写的函数知道迭代器的大小,操作的作用,可以内联操作并将迭代器的实例作为值存储在缓冲区或堆栈中。除非迭代器强制执行,否则不会进行虚拟调度,并且如果可见操作,则可以将其内联到编写的函数中。

紧密循环可以由编译器检查,并且可以进行矢量化,就像您手动编写函数一样。

同一模板可以对数据库条目或字符串或整数进行排序;在每种情况下,都会编写一个新函数,并告诉编译器尝试使其更快。

TL; DR

迭代器不是类型;他们是一种类型。完全不相关的类型都可以是迭代器。迭代器没有基类;他们有某些保证行为的方法。

C ++算法会为您传递给std::vector<?>::iterator的每种迭代器类型生成自定义代码;如果对int向量和字符串向量进行排序,则两者之间不会共享二进制代码(comdat折叠的可能性除外)。

概念(类型)Iterator / ForwardIterator / RandomAccessIterator是对传递给C ++算法的类型的记录要求。没有执行任何操作,除了编译器可以在不满足要求的情况下自由地执行任何操作之外。

答案 2 :(得分:0)

迭代器是一种行为设计模式,被概括为“四个设计模式的帮派”的一部分。它解决了在不知道该对象内部结构的情况下遍历聚合对象中的对象的问题。

有关迭代器模式的更多详细信息,请参阅以下内容: http://www.blackwasp.co.uk/Iterator.aspx