为什么需要它!=obj.end() 尽管每个迭代器都应该知道自己何时终止
why does it need it!=obj.end() although every iterator should know itself when to terminate?
下面的问题刚刚在我脑海中闪过。对于 c++ stl 迭代器,常见的做法是具有如下内容:
for (iterator it=obj.begin(); it!=obj.end(); it++)
我想知道的是,obj.begin(( 实际上可以告诉"它"何时停止,这将使 for 循环看起来像:
for (iterator it=obj.begin(); !it.end(); it++)
好处是使迭代器更加独立,并且可以将(迭代器end(((保存在容器类中。
有时,除了循环访问容器的全部内容之外,您还想执行其他操作。 例如,您可以创建一对迭代器,这些迭代器将仅迭代容器的前半部分。 因此,使用单独的对象来表示结束更加灵活,因为它允许用户更好地控制放置范围末尾的位置。
你是对的,对于迭代所有内容的最常见情况来说,这有点不方便。 但是,C++11 提供了一个基于范围的 for 循环,这使得在整个容器上进行循环变得非常容易,所以就像编程中的许多事情一样,它实际上只是选择正确的结构来最好地表达你的意图的问题。
如果迭代器 API 是这样设计的,指针将不是有效的迭代器(因为指针显然没有 end()
(方法。因此,这将排除为具有连续内存的数据结构实现迭代器的最直接方法。
一些库提供"java 风格的迭代器",其工作方式与您描述的类似。
然而,这个方案(hasNext()
等(的最大问题是这样的迭代器是类。
例如,STL包含<algorithm>
头文件,其中包含std::copy
、std::generate
、std::sort
、std::lower_bound
、std::fill
等函数。所有这些例程都使用开始/结束样式迭代器。因此,您可以将指针与这些函数一起使用。如果这些函数在作为类的迭代器上运行(即,如果它们在内部调用hasNext()
而不是!= end()
(,那么您将无法将指针传递到 std::sort 等。在这种情况下,您必须将所有内容包装到类中,浪费您的时间,并且失去对<algorithm>
的访问权限不值得通过向迭代器类添加atEnd()
方法获得小小的便利。这可能就是将迭代器与end()
进行比较的原因。
迭代器不需要"知道"容器。它可能只知道并关心内存块或当前节点(或任何适合正在迭代的数据结构(中的偏移量,而不知道包含容器的任何信息。例如,vector
迭代器可以作为一个简单的指针实现,而不知道(本身(向量在哪里结束。
此外,STL 算法也需要处理原始指针,因此迭代器需要"模仿"指针。
STL 发明时(由 Stepanov 在 90 年代初(做出的决定,后来在C++标准化过程中获得批准,迭代器将是指针的泛化。从 http://www.sgi.com/tech/stl/stl_introduction.html:
在反转 C 数组的示例中,要反转的参数是 显然属于
double*
型.如果你是,有什么论点可以逆转 但是,反转向量还是列表?...答案是 反转的参数是迭代器,它是 指针。
迭代器不必是指针的泛化。C++标准库(以及在此之前的 STL(理论上可以使用不同的迭代模型,其中迭代将由单个迭代器对象或单个范围对象表示,而不是由一对迭代器表示 first
和 last
。
我认为不会有太大的性能差异。现代C++编译器肯定不会有。STL(以及基于它的标准库(始终依赖于编译器体面的内联来提高性能,并且这些类不会比编译器在容器内部已经必须处理的类更糟糕。提供一个简单的包装器,将一对指针转换为迭代器或范围对象也不会有任何重大困难。
有些人确实更喜欢其他迭代器模型 - James Gosling(或者如果不是他,谁设计了Java迭代器(。有些人更喜欢范围(包括大量的C++程序员:因此是Boost.Range(。
我怀疑 STL 的作者和C++喜欢这样一个事实,即 STL 风格的迭代器保留了与 C 的某种兼容性,你可以采用一种 C 算法,该算法使用指针对数组(或用户使用一对指针指定的其他范围(进行操作,并将其几乎不变地转换为使用迭代器对容器(或其他范围(进行操作的C++算法。这种想法意味着你的新语言可以更容易地被现有的用户群吸收,这是C++早期的目标之一。
因此,像"我们能否提供一种测试结束的方法,它缩短了几个字符,代价是使指针不再是迭代器并使迭代器更大",当时可能不会引起太多兴趣。但那是那时,例如安德烈·亚历山德雷斯库(Andrei Alexandrescu(已经敲打了一段时间,在他看来,这不再是最佳选择,而且范围比迭代器更好。
让迭代器以它的方式工作,可以灵活地处理子范围。您不必总是从begin()
开始或以end()
结束。例如,如果要使用包含特定值的所有迭代器,则可以使用 equal_range()
的返回值作为开始和结束。
D 语言有一个包含迭代器范围的开始和结束的range
。它也被提议用于C++:http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/7e52451ed8eea31c
知道迭代器的begin
和end
(以及rbegin
和rend
(在哪里当然是有用的,但你陈述的情况在某种程度上是由 C++11 的基于范围的 for
循环处理的:
for (auto it: obj)
{
// Do something with *it;
}
在 C++11 中完成工作要容易得多,而无需编写太多样板!
- 使用std::multimap迭代器创建std::list
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++中带有List类的迭代器Segfault
- 如何在c++迭代器类型中包装std::chrono
- 集合上的输出迭代器:assign和increment迭代器
- Boost Spirit,获取迭代器内部语义动作
- 对于set上的循环-获取next元素迭代器
- 为什么output_editor Concept不需要output_e迭代器标记
- c++17文件系统::recursive_directory迭代器()在mac上没有给出这样的目录,但在windows上
- 使用迭代器时如何访问对象在向量中的位置?
- std::vector::迭代器是否可以合法地作为指针
- 跟随整数索引列表的自定义类迭代器
- 不明白迭代器,引用和指针失效,一个例子
- 我可以使用反向迭代器作为ForwardIt吗
- ESP8266单片机矢量迭代器的C++问题
- std::使用迭代器映射查找距离,程序不会终止
- 使用 nullptr 终止迭代器
- 为什么需要它!=obj.end() 尽管每个迭代器都应该知道自己何时终止
- c++boost迭代器抛出断言,程序终止
- 在处理迭代器时被信号SIGSEGV(地址边界错误)终止