了解 STL 中的迭代器
Understanding Iterators in the STL
C++STL中的迭代器到底是什么?
就我而言,我使用的是list
,我不明白为什么您必须创建一个迭代器std::list <int>::const_iterator iElementLocator;
才能通过 dereference 运算符显示列表的内容:
cout << *iElementLocator;
将其分配给可能list.begin()
.
请解释迭代器到底是什么以及为什么我必须取消引用或使用它。
STL 中有三个构建块:
- 器皿
- 算法
- 迭代器
在概念级别,容器保存数据。这本身并不是很有用,因为您想对数据做一些事情;你想对它进行操作,操纵它,查询它,玩它。算法正是这样做的。但是算法不保存数据,它们没有数据——它们需要一个容器来完成这项任务。将容器交给算法,您就会执行操作。
唯一需要解决的问题是,从技术角度来看,算法如何遍历容器。从技术上讲,容器可以是链表,也可以是数组、二叉树或任何其他可以保存数据的数据结构。但是遍历数组与遍历二叉树不同。尽管从概念上讲,算法想要的只是一次从容器中"获取"一个元素,然后处理该元素,但从容器中获取下一个元素的操作在技术上是非常特定于容器的。
看起来好像需要为每个容器编写相同的算法,以便每个版本的算法都有正确的代码来遍历容器。但是有一个更好的解决方案:要求容器返回一个可以遍历容器的对象。该对象将具有算法知道的接口。当算法要求对象"获取下一个元素"时,对象将遵守。因为对象直接来自容器,所以它知道如何访问容器的数据。由于对象具有算法知道的接口,因此我们不需要为每个容器复制算法。
这是迭代器。
这里的迭代器将算法粘附到容器上,而不耦合两者。迭代器耦合到容器,算法耦合到迭代器的接口。这里魔力的来源实际上是模板编程。考虑标准copy()
算法:
template<class In, class Out>
Out copy(In first, In last, Out res)
{
while( first != last ) {
*res = *first;
++first;
++res;
}
return res;
}
copy()
算法将类型In
上的两个迭代器和一个类型为 Out
的迭代器作为参数。它将从位置 first
开始并在位置 last
之前结束的元素复制到 res
中。该算法知道要获得下一个元素,它需要说 ++first
或 ++res
.它知道要读取一个元素,它需要说x = *first
,写一个元素它需要说*res = x
。这是算法假设和迭代器承诺的接口的一部分。如果错误地迭代器不符合接口,那么当类型未定义函数时,编译器将发出错误,以通过类型 In
或 Out
调用函数。
我很懒。所以我不会输入描述迭代器是什么以及如何使用它们,特别是当网上已经有很多文章可以自己阅读时。
以下是我可以首先引用的一些内容,提供完整文章的链接:
MSDN 说,
迭代器是 指针,从其抽象 要求以允许 C++程序与不同的 统一方式的数据结构。 迭代器充当中介 在容器和泛型之间 算法。而不是在 具体的数据类型,算法是 定义为在某个范围内操作 由迭代器类型指定。任何 满足以下条件的数据结构 然后迭代器的要求 由算法操作。那里 是五种类型或类别 迭代器 [...]
顺便说一下,MSDN 似乎已经从标准本身中获取了粗体文本C++特别是来自 §24.1/1 部分,其中
迭代器是 允许C++程序的指针 使用不同的数据结构 (容器(以统一的方式。自 能够构建模板 正常工作的算法和 高效处理不同类型的数据 结构,库形式化不 只是接口,还有 语义和复杂性假设 的迭代器。我支持的所有迭代器 表达式 *i,导致 某个类的值、枚举或 内置类型 T,称为值类型 的迭代器。所有迭代器 i 为 其中表达式 (*i(.m 是 定义明确,支持表达式 具有相同语义的 I->m (*一(.对于每个迭代器,键入 X 用于 定义了哪个平等,有一个 对应有符号积分类型 称为差分类型 迭 代。
cplusplus 说,
在C++中,迭代器是任何对象 那,指向 元素范围(例如数组或 容器(,具有 遍历其中的元素 范围使用一组运算符(在 最小,增量 (++( 和 取消引用 (*( 运算符(。
迭代器最明显的形式是 指针 [...]
您还可以阅读这些:
- 什么是迭代器?
- 标准C++库中的迭代器
- 迭代器(在维基条目中(
请耐心阅读所有这些内容。希望您能对迭代器有所了解,C++。学习C++需要耐心和时间。
迭代器与容器本身不同。迭代器引用容器中的单个项,并提供访问其他项的方法。
考虑设计自己的容器,而不使用迭代器。它可以具有size
函数来获取它包含的项目数,并且可以重载[]
运算符以允许您按位置获取或设置项目。
但是这种"随机访问"不容易在某些类型的容器上有效实现。如果您获得第 100 万个项目:c[1000000]
并且容器内部使用链表,则它必须扫描一百万个项目才能找到您想要的项目。
您可以改为决定允许集合记住"当前"项。它可以具有start
和next
more
等功能,并允许您循环访问内容:
c.start();
while (c.more())
{
item_t item = c.next();
// use the item somehow
}
但这会将"迭代状态"放在容器中。这是一个严重的限制。如果要将容器中的每个项目与其他每个项目进行比较,该怎么办?这需要两个嵌套循环,都遍历所有项目。如果容器本身存储迭代的位置,则无法嵌套两个这样的迭代 - 内部循环将破坏外部循环的工作。
因此,迭代器是迭代状态的独立副本。您可以开始迭代:
container_t::iterator i = c.begin();
该迭代器i
是一个单独的对象,表示容器内的位置。您可以获取存储在该位置的任何内容:
item_t item = *i;
您可以移动到下一项:
i++;
使用某些迭代器,您可以向前跳过几个项目:
i += 1000;
或者获取相对于迭代器标识的位置的某个位置的项目:
item_t item = i[1000];
使用一些迭代器,您可以向后移动。
您可以通过将迭代器与end
进行比较来发现您是否超出了容器的内容:
while (i != c.end())
您可以将end
视为返回一个迭代器,该迭代器表示超出容器中最后一个位置的位置。
迭代器(以及一般情况下C++(需要注意的重要一点是,它们可能会变得无效。例如,如果您清空容器,通常会发生这种情况:指向该容器中位置的任何迭代器现在都变得无效。在这种状态下,对它们的大多数操作都是未定义的 - 任何事情都可能发生!
迭代器之于STL容器,就像指针之于数组一样。您可以将它们视为指向 STL 容器的指针对象。作为指针,您将能够将它们与指针符号一起使用(例如 *iElementLocator
,iElementLocator++
(。作为对象,它们将具有自己的属性和方法 (http://www.cplusplus.com/reference/std/iterator(。
已经有很多关于迭代器的良好解释。只是谷歌它。
举个例子。
如果有什么具体的事情你不明白,回来问问。
我建议阅读有关C++运算符重载的信息。这将说明为什么*
和->
基本上可以意味着任何东西。只有这样,您才应该阅读有关迭代器的信息。否则,它可能显得非常混乱。
- 自定义 STL 兼容迭代器,用于迭代 2D 数组类的列
- "迭代器"和"const_iterator"不是 STL 容器的必需成员?
- 没有 STL 容器的迭代器
- 为什么某些 STL 容器(堆栈、队列、优先级队列)不支持迭代器?
- 迭代器 STL C++是模板、类还是接口?
- 为什么我们不在 STL 的迭代器中传递星号(*)
- 成员函数不能为集合迭代器和const_iterator的输入重载(但可以为其他 STL 迭代器重载)
- 如何在C++中重新实现包含指针的 STL 容器的类的迭代器
- C++如何获取传递给函数(STL 迭代器)的参数的名称
- 迭代器和 STL 容器的关系
- C++ 中 STL 中迭代器的大小(以字节为单位)是多少
- 如何将 stl 迭代器与特征一起使用?
- 用于 STL 迭代器、指针和 std::nullptr_t 的模板函数
- 在 stl 容器包装器中定义迭代器类型
- 在多个 STL 对对象上创建迭代器
- 如何为获取 stl 容器迭代器的函数提供函数签名?
- 在 stl 算法中移动迭代器
- lower_bound 在 C++ STL 中返回迭代器,即使元素不存在也是如此.如何避免这种情况?
- 并行STL插入迭代器,例如std :: back_insert_iterator
- STL 迭代器继承:"value_type"不命名类型