在经过各种STL算法(例如std :: search,std :: search_n,std :: lower_bound)的模板定义之后,您必须找到其模板定义,这些模板定义由Forward Iterator类型的对象组成。那么,它们是什么?为什么要使用它们?
前向迭代器是C++标准库中存在的五种主要迭代器之一,其他类型是输入迭代器,输出迭代器,双向迭代器和随机访问迭代器。
正向迭代器被视为输入迭代器和输出迭代器的组合。它为它们两者的功能提供支持。它允许访问和修改值。
要记住的一件事是双向和随机访问迭代器也是有效的前向迭代器,如上面的迭代器层次结构所示。
显着特征
- 可用性:在可取消引用的正向迭代器上执行操作永远不会使其迭代器值不可引用,因此,这使使用此类迭代器的算法可以使用一个迭代器的多个副本,以相同的迭代器值多次传递。因此,它可以用于多遍算法中。
- 相等/不相等比较:可以将前向迭代器与另一个迭代器进行相等性比较。由于迭代器指向某个位置,因此这两个迭代器仅在指向相同位置时才相等,否则就不相等。
因此,如果A和B是正向迭代器,则以下两个表达式有效:
A == B // Checking for equality A != B // Checking for inequality
- 解除引用:由于可以对输入迭代器进行解引用,因此可以使用运算符*和->作为右值,而将输出迭代器作为左值进行解引用,因此正向迭代器可同时用于这两个目的。
// C++ program to demonstrate forward iterator #include
#include using namespace std; int main() { vector v1 = { 1, 2, 3, 4, 5 }; // Declaring an iterator vector ::iterator i1; for (i1 = v1.begin(); i1 != v1.end(); ++i1) { // Assigning values to locations pointed by iterator *i1 = 1; } for (i1 = v1.begin(); i1 != v1.end(); ++i1) { // Accessing values at locations pointed by iterator cout << (*i1) << " "; } return 0; } 输出:
1 1 1 1 1
因此,正如我们在此处看到的那样,我们既可以访问迭代器,也可以为其分配值,因此,该迭代器至少是一个正向迭代器(它在层次结构中也可以更高)。
- 可递增的:前向迭代器可以递增,以便使用运算符++()引用序列中的下一个元素。
注意:我们可以将前向迭代器与增量运算符一起使用的事实并不意味着运算符–-()也可以与它们一起使用。请记住,前向迭代器是单向的,只能向前移动。
因此,如果A是正向迭代器,则以下两个表达式有效:
A++ // Using post increment operator ++A // Using pre increment operator
- 可交换的:这些迭代器指向的值可以交换或交换。
实际实施
了解了它的功能之后,了解它的实际实现也非常重要。如前所述,正向迭代器既可以在我们要访问元素时使用,也可以在必须为其分配元素时使用,因为它是输入和输出迭代器的组合。以下两种STL算法可以显示这一事实:
- std :: replace:众所周知,该算法用于将范围内等于特定值的所有元素替换为新值。因此,让我们看一下它的内部工作原理(不要再去研究细节了,而是看看可以在哪里使用正向迭代器,而不能在何处使用正向迭代器):
// Definition of std::replace() template void replace(ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value) { while (first != last) { if (*first == old_value) // L1 *first = new_value; // L2 ++first; } }
在这里,我们可以看到我们使用了正向迭代器,因为我们需要同时使用输入和输出迭代器的功能。在L1中,我们需要首先将迭代器作为rvalue(输入迭代器)解引用,而在L2中,我们首先需要将其迭代器作为lvalue(输出迭代器)解引用,因此为了完成这两项任务,我们使用了正向迭代器。
- std :: reverse_copy:顾名思义,此算法用于将一个范围复制到另一个范围,但顺序相反。现在,就访问元素和分配元素而言,前向迭代器就可以了,但是一旦我们必须递减迭代器,就不能为此目的使用这些前向迭代器。
// Definition of std::reverse_copy() template OutputIterator reverse_copy(BidirectionalIterator first, BidirectionalIterator last, OutputIterator result) { while (first != last) *result++ = *--last; return result; }
在这里,我们可以看到我们将last声明为双向迭代器,而不是正向迭代器,因为我们不能像last那样减少正向迭代器,因此在这种情况下我们不能使用它。
注意:正如我们所知,前向迭代器是输入和输出迭代器的组合,因此,如果任何算法都涉及到使用这两个迭代器中的任何一个,那么我们也可以在它们的位置使用前向迭代器,而不会影响程序。
因此,以上两个例子很好地说明了何时,何地,为什么以及如何实际使用正向迭代器。
局限性
在研究了显着特征之后,还必须知道其缺陷,尽管输入或输出迭代器中的缺陷不如层次结构中较高的迭代器。
- 不能减少:就像我们可以将运算符++()与正向迭代器一起使用来增加它们一样,我们也不能减少它们。尽管它在层次结构中比输入和输出迭代器高,但仍不能克服此缺陷。
这就是为什么它的名字是向前的,这表明它只能沿向前的方向移动。
If A is a forward iterator, then A-- // Not allowed with forward iterators
- 关系运算符:尽管前向迭代器可以与相等运算符(==)一起使用,但不能与=等其他关系运算符一起使用。
If A and B are forward iterators, then A == B // Allowed A <= B // Not Allowed
- 算术运算符: -等方面的关系运算符相似,而且还不能与算术运算运算符如+,使用。这意味着向前的运算符只能在一个方向过于向前和顺序太远的方向上移动。
If A and B are forward iterators, then A + 1 // Not allowed B - 2 // Not allowed
- 使用偏移量解除引用运算符([]):前向迭代器不支持用于随机访问的偏移量解除引用运算符([])。
If A is a forward iterator, then A[3] // Not allowed