Output Iterators: What does it mean that "we may assign to a given value of an output iterator only once"?

From C++ Primer, Lippman, Section 10.5.1. "The Five Iterator Categories"
Output Iterators can be thought of as having complementary functionality to input iterators; they write rather than read elements. Output iterators must provide:

+ Prefix and postfix increment (++) to advance the iterator
+ Dereference (*) which may appear only as the left-hand side of an assignment (Assigning to a dereferenced output iterator writes tot he underlying element).

We may assign to a given value of an output iterator only once. Like input iterators, output iterators may be used only for single-pass algorithms.


I have some questions about this passage.

1. What does it mean when the author says "we may assign to a given value of an output iterator only once"? Surely this can't mean you can assign to an output iterator only once (below, I've assigned to oitr twice and it was ok.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include <string>
#include <iterator> // iostream iterators
#include <typeinfo> 

using std::cout;
using std::istream;
using std::ostream;
using std::string;
using std::istream_iterator;
using std::ostream_iterator;

template <typename ITERATOR>
void PrintIteratorCategory() 
{
    if (typeid(typename std::iterator_traits<ITERATOR>::iterator_category) == typeid(std::input_iterator_tag)) {
        cout << "Input Iterator"; 
    } else if (typeid(typename std::iterator_traits<ITERATOR>::iterator_category) == typeid(std::output_iterator_tag)) {
        cout << "Output Iterator";   
    } else if (typeid(typename std::iterator_traits<ITERATOR>::iterator_category) == typeid(std::forward_iterator_tag)) {
        cout << "Forward Iterator";   
    } else if (typeid(typename std::iterator_traits<ITERATOR>::iterator_category) == typeid(std::bidirectional_iterator_tag)) {
        cout << "Bidirectional Iterator";   
    } else if (typeid(typename std::iterator_traits<ITERATOR>::iterator_category) == typeid(std::random_access_iterator_tag)) {
        cout << "Random Access Iterator";   
    }
    cout << "\n";
}

int main()
{
    PrintIteratorCategory<ostream_iterator<int>>(); // "Output Iterator"

    ostream_iterator<string> oitr(cout);
    oitr = "Hello ";
    oitr = "World!";
    
    return 0; 
}


2. The passage on Forward Iterator states:
Forward iterators support all the operations of both input iterators and output iterators. Moreover, they can read or write the same element multiple times.

Can someone give an example of "writing to the same element multiple times" with a Foward iterator?

3. I've heard of the terms "single-pass" and "multi-pass" used to describe both iterators and algorithms. What is a single/multi-pass iterator?

Drives me nuts that there are few code examples in this chapter.
Last edited on
> 1. What does it mean when the author says "we may assign to a given value of an output iterator only once"?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <vector>
#include <iterator>

template < typename ITERATOR > requires requires( ITERATOR i ) { *i = 1 ; }
void foo( ITERATOR iter )
{
    ITERATOR saved = iter ;
    *iter = 10 ;
    *iter = 20 ;
    *saved = 30 ;
}

int main()
{
    std::vector<int> vec{ 0, 1, 2, 3, 4, 5 } ;
    const auto forward_iterator = vec.begin() ;
    foo( forward_iterator ) ; // Forward iterators can read or write to the same element multiple times.
                              // foo assigns to the same value - the one 'pointed to' by the iterator - three times
    std::cout << vec.front() << '\n' ; // 30

    const auto output_iterator = std::back_inserter(vec) ;
    foo(output_iterator) ; // we may assign to a *given value* of an output iterator only once
                           // foo assigns to *three different values* of the output iterator
                           // (adds three more items to the back of the container; ie. adds 10, 20 and 30)
     std::cout << vec.size() << '\n' ; // 9 ie. vec contains { 0, 1, 2, 3, 4, 5, 10, 20, 30 }
}


> What is a single/multi-pass iterator?

Single-pass iterator: using this iterator, the sequence can only be traversed once. For example, once we have read a value with an input stream iterator, we can't undo/ignore the previous read and read the same value once again.

Multi-pass iterator: with such an iterator, we can iterate through the sequence multiple times. With a copy of the iterator, we can remember a position within the sequence and go back to it if needed.
Topic archived. No new replies allowed.