完成各种STL算法(例如std :: copy , std :: move , std :: transform)的模板定义之后,您必须找到由Output Iterator类型的对象组成的模板定义。那么,它们是什么?为什么要使用它们?
输出迭代器是C++标准库中存在的五种主要迭代器之一,其他类型是输入迭代器,正向迭代器,双向迭代器和随机访问迭代器。
由于输出迭代器执行与输入迭代器相反的函数,因此它们被认为与输入迭代器完全相反。可以按顺序为它们分配值,但是不能将它们用于访问值,这与输入迭代器不同,后者迭代访问值并且不能分配值。因此,可以说输入和输出迭代器是互补的。
要记住的一件事是,前向,双向和随机访问迭代器也是有效的输出迭代器,如上面的迭代器层次结构所示。
显着特征
- 可用性:就像输入迭代器一样,输出迭代器只能与单遍算法一起使用,即,我们最多可以一次访问范围内的所有位置的算法,因此这些位置只能被取消引用或分配值一次。
- 相等/不相等比较:与输入迭代器不同,不能将输出迭代器与另一个迭代器进行相等性比较。
因此,如果A和B是输出迭代器,则以下两个表达式无效:
A == B // Invalid - Checking for equality A != B // Invalid - Checking for inequality
- 取消引用:使用运算符*和->可以将输入迭代器作为rvalue取消引用,而可以将输出迭代器作为lvalue取消引用,以提供存储值的位置。
因此,如果A是输出迭代器,则以下两个表达式有效:
*A = 1 // Dereferencing using * A -> m = 7 // Assigning a member element m
- 可递增的:可以使用运算符++()递增输出迭代器,以使其引用顺序中的下一个元素。
因此,如果A是输出迭代器,则以下两个表达式有效:
A++ // Using post increment operator ++A // Using pre increment operator
- 可交换的:这些迭代器指向的值可以交换或交换。
实际实施
了解了它的特性和不足之后,了解其实际实现也非常重要。如前所述,仅在我们要分配元素时才使用输出迭代器,而在必须访问元素时则不使用输出迭代器。以下两种STL算法可以显示这一事实:
- std :: move:顾名思义,此算法用于将一个范围内的元素移动到另一个范围内。现在,就访问元素而言,输入迭代器就可以了,但是一旦我们必须在另一个容器中分配元素,就不能为此目的使用这些输入迭代器,这就是为什么在这里使用输出迭代器成为强制的原因。
// Definition of std::move() template OutputIterator move (InputIterator first, InputIterator last, OutputIterator result) { while (first!=last) { *result = std::move(*first); ++result; ++first; } return result; }
在这里,由于结果是分配给元素的结果容器的迭代器,因此,为此,我们不能使用输入迭代器并在其位置使用输出迭代器,而对于访问元素,仅使用输入迭代器需要增加和访问。
- std :: find:我们知道该算法用于查找容器中元素的存在,并且不涉及使用输出迭代器。
// Definition of std::find() template InputIterator find (InputIterator first, InputIterator last, const T& val) { while (first!=last) { if (*first==val) return first; ++first; } return last; }
因此,从这里开始,不需要为迭代器分配值,只需要访问和比较迭代器,因此不需要输出迭代器,因此仅使用了输入迭代器。
因此,以上两个示例很好地显示了何时,何地,为什么以及如何实际使用输出迭代器。
局限性
在研究了显着特征之后,还必须知道输出迭代器的不足,以下几点将提到这些不足:
- 仅分配,不访问:最大的不足之一是我们无法以rvalue的形式访问输出迭代器。因此,输出迭代器只能用作分配目标,才能修改其指向的元素。
// C++ program to demonstrate output 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 elements using iterator *i1 = 1; } // v1 becomes 1 1 1 1 1 return 0; } 上面是使用输出迭代器分配元素的示例,但是,如果执行以下操作:
a = *i1 ; // where a is a variable
因此,这对于输出迭代器是不允许的,因为它们只能是分配中的目标。但是,如果对上面的代码尝试此操作,则它将起作用,因为向量在层次结构上返回的迭代器要比输出迭代器高。
这种严重的不足是为什么很多算法(如std :: find)需要访问范围中的元素并检查是否相等的原因,因此无法使用输出迭代器执行此操作,因为我们无法使用它来访问值,因此我们改为使用输入迭代器。
- 不能递减:就像我们可以将运算符++()与输出迭代器一起使用来递增它们一样,我们也不能递减它们。
If A is an output iterator,then A-- // Not allowed with output iterators
- 在多遍算法中使用:由于它是单向的,只能向前移动,因此,此类迭代器不能用于多遍算法中,因为我们需要多次遍历容器。
- 关系运算符:就像输出迭代器不能与相等运算符(==)一起使用一样,它也不能与其他关系运算符(如=)一起使用。
If A and B are output iterators, then A == B // Not Allowed A <= B // Not Allowed
- 算术运算符: -等方面的关系运算符相似,而且还不能与算术运算运算符如+,使用。这意味着输出运算符只能沿太过向前和太过顺序的一个方向移动。
If A and B are output iterators, then A + 1 // Not allowed B - 2 // Not allowed