📜  C++中的输出迭代器

📅  最后修改于: 2021-05-30 04:54:41             🧑  作者: Mango

完成各种STL算法(例如std :: copystd :: movestd :: transform)的模板定义之后,您必须找到由Output Iterator类型的对象组成的模板定义。那么,它们是什么?为什么要使用它们?

输出迭代器是C++标准库中存在的五种主要迭代器之一,其他类型是输入迭代器正向迭代器双向迭代器随机访问迭代器

由于输出迭代器执行与输入迭代器相反的函数,因此它们被认为输入迭代器完全相反。可以按顺序为它们分配值,但是不能将它们用于访问值,这与输入迭代器不同,后者迭代访问值并且不能分配值。因此,可以说输入和输出迭代器是互补的

要记住的一件事是,前向双向随机访问迭代器也是有效的输出迭代器,如上面的迭代器层次结构所示。

显着特征

  1. 可用性:就像输入迭代器一样,输出迭代器只能与单遍算法一起使用,即,我们最多可以一次访问范围内的所有位置的算法,因此这些位置只能被取消引用或分配值一次。
  2. 相等/相等比较:与输入迭代器不同,不能将输出迭代器与另一个迭代器进行相等性比较。

    因此,如果A和B是输出迭代器,则以下两个表达式无效:

    A == B  // Invalid - Checking for equality
    A != B  // Invalid - Checking for inequality
    
  3. 取消引用:使用运算符*和->可以将输入迭代器作为rvalue取消引用,而可以将输出迭代器作为lvalue取消引用,以提供存储值的位置。

    因此,如果A是输出迭代器,则以下两个表达式有效:

    *A = 1      // Dereferencing using *
    A -> m = 7   // Assigning a member element m
    
  4. 可递增的:可以使用运算符++()递增输出迭代器,以使其引用顺序中的下一个元素。

    因此,如果A是输出迭代器,则以下两个表达式有效:

    A++   // Using post increment operator
    ++A   // Using pre increment operator
    
  5. 可交换的:这些迭代器指向的值可以交换或交换。

实际实施

了解了它的特性和不足之后,了解其实际实现也非常重要。如前所述,仅在我们要分配元素时才使用输出迭代器,而在必须访问元素时则不使用输出迭代器。以下两种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;
    }
    

    因此,从这里开始,不需要为迭代器分配值,只需要访问和比较迭代器,因此不需要输出迭代器,因此仅使用了输入迭代器。

因此,以上两个示例很好地显示了何时,何地,为什么以及如何实际使用输出迭代器。

局限性

在研究了显着特征之后,还必须知道输出迭代器的不足,以下几点将提到这些不足:

  1. 仅分配,不访问:最大的不足之一是我们无法以rvalue的形式访问输出迭代器。因此,输出迭代器只能用作分配目标,才能修改其指向的元素。
    // C++ program to demonstrate output iterator
    #include
    #include
    using namespace std;
    int main()
    {
        vectorv1 = {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)需要访问范围中的元素并检查是否相等的原因,因此无法使用输出迭代器执行此操作,因为我们无法使用它来访问值,因此我们改为使用输入迭代器。

  2. 不能递减:就像我们可以将运算符++()与输出迭代器一起使用来递增它们一样,我们也不能递减它们。
    If A is an output iterator,then
    
    A--    // Not allowed with output iterators
    
  3. 在多遍算法中使用:由于它是单向的,只能向前移动,因此,此类迭代器不能用于多遍算法中,因为我们需要多次遍历容器。
  4. 关系运算符:就像输出迭代器不能与相等运算符(==)一起使用一样,它也不能与其他关系运算符(如=)一起使用。
    If A and B are output iterators, then
    
    A == B     // Not Allowed
    A <= B     // Not Allowed
    
  5. 算术运算符: -等方面的关系运算符相似,而且还不能与算术运算运算符如+,使用。这意味着输出运算符只能沿太过向前和太过顺序的一个方向移动。
    If A and B are output iterators, then
    
    A + 1     // Not allowed
    B - 2     // Not allowed
    
要从最佳影片策划和实践问题去学习,检查了C++基础课程为基础,以先进的C++和C++ STL课程基础加上STL。要完成从学习语言到DS Algo等的更多准备工作,请参阅“完整面试准备课程”