嗨,所以我对迭代器以及它们实际上是什么有点困惑....在C ++ STL中
在这种情况下我使用列表,我不明白你为什么要做一个迭代器:
std::list <int>::const_iterator iElementLocator;
由derefrence运算符dipslay列表的内容:
cout << *iElementLocator;
将其分配给list.begin();
请解释一下迭代器的确切含义以及为什么我必须解除它/使用它! 的谢谢!
答案 0 :(得分:18)
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
上的函数。
答案 1 :(得分:6)
我很懒。所以我不打算描述迭代器是什么以及它们是如何被使用的,特别是当你已经有很多在线文章可以自己阅读时。
这里有一些我可以引用的开头,可以提供完整文章的链接:
MSDN说,
迭代器是一种概括 指针,从他们的抽象 要求以允许的方式 与不同的C ++程序一起工作 数据结构统一。 迭代器充当中介 容器和通用之间 算法。而不是操作 具体的数据类型,算法都是 定义为在一个范围内操作 由迭代器类型指定。任何 满足的数据结构 然后可能需要迭代器 由算法操作。那里 是五种类型或类别 迭代器[...]
顺便说一下,似乎MSDN已经从C ++标准本身采用粗体文本,特别是来自§24.1/ 1的部分
迭代器是一种概括 允许C + +程序的指针 使用不同的数据结构 (容器)以统一的方式。 To 能够构建模板 正确运行的算法 有效地处理不同类型的数据 结构,图书馆没有形式化 只是接口而且还有 语义和复杂性假设 迭代器。我支持的所有迭代器 表达式* i,导致a 某些类的值,枚举或 内置类型T,称为值类型 迭代器。所有迭代器我都是 其中表达式(* i).m是 定义明确,支持表达 i-&gt; m具有与之相同的语义 (* I).M。对于每个迭代器类型X for 哪个等式定义,有一个 相应的有符号整数型 称为差异类型 迭代器。
在C ++中,迭代器是任何对象 那,指向一个元素 元素范围(例如数组或 一个容器),有能力 遍历那些元素 范围使用一组运算符(at 至少,增量(++)和 dereference(*)operator)。
最明显的迭代器形式是 指针[...]
你也可以阅读这些:
有耐心并阅读所有这些。希望您能在C ++中了解迭代器是什么。学习C ++需要耐心和时间。
答案 2 :(得分:2)
迭代器是指向STL容器的指针指向数组的内容。您可以将它们视为STL容器的指针对象。作为指针,您将能够使用指针表示法(例如*iElementLocator
,iElementLocator++
)。作为对象,它们将具有自己的属性和方法(http://www.cplusplus.com/reference/std/iterator)。
答案 3 :(得分:2)
迭代器与容器本身不同。迭代器引用容器中的单个项目,并提供到达其他项目的方法。
考虑在没有迭代器的情况下设计自己的容器。它可以有一个size
函数来获取它包含的项目数,并且可以使[]
运算符超载,以允许您根据其位置获取或设置项目。
但是那种“随机访问”并不容易在某些容器上有效实现。如果您获得了第一百万项:c[1000000]
并且容器内部使用链接列表,则必须扫描一百万个项目才能找到您想要的项目。
您可能会决定允许集合记住“当前”项目。它可以包含start
和more
以及next
等功能,以便您遍历内容:
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 ++中)注意的一个重点是它们可能变得无效。例如,如果清空容器,通常会发生这种情况:指向该容器中位置的任何迭代器现在都变为无效。在那种状态下,对它们的大多数操作都是未定义的 - 任何事情都可能发生!
答案 4 :(得分:0)
答案 5 :(得分:0)
我建议在C ++中阅读有关运算符重载的内容。这将说明为什么*
和->
基本上可以表示任何内容。只有这样你才能阅读迭代器。否则它可能看起来很混乱。