user2393256 user2393256 - 18 days ago 7
C++ Question

istream_iterator consumes too much from stream

I get the following input from stdin:

2
5
2 1 5 3 4
5
2 5 1 3 4


The first line represents the number of queues (let's call this value
n
). Then, for each queue, on the first line there is a value
l
that is denoting the length of the queue, followed by the actual queue.

I am trying to put the queues in a vector using an
istream_iterator
as follows:

using namespace std;
int n{};
int l{};
typedef std::istream_iterator<int> input_iterator;
cin >> n;
cout<< "n: " << n << "\n";
for(int i = 0; i < n ; ++i){

cin >> l;
cout << "l: " << l << "\n";
std::vector<int> queue;
int counter = 0;
for (input_iterator it(cin); counter < l && it != input_iterator(); ++it){
queue.push_back((*it));
++counter;
}
cout<< "Queue: ";
std::copy(queue.begin(), queue.end(),
std::ostream_iterator<int>(std::cout, " "));
cout << "\n";
}


This code produces the following output:

n: 2
l: 5
Queue: 2 1 5 3 4
l: 2
Queue: 5 1


As you can see the first queue is read correctly. But the second
l
should be
5
, not
2
.

What is happening to the
5
? Is it consumed by the iterator? Where did i make an error?

Answer

Your problem is that your for-loop leaves i in a position next to the last element of the queue. So when calling operator>> to acquire the next value for l, you are one "reading step" too far.

To avoid the problem, you can use the same iterator for all your reading operations -- and rename it to avoid name collision with the variable i in the outer loop, like this:

using namespace std;
int n{};
int l{};
typedef std::istream_iterator<int> input_iterator;
cin >> n;
cout<< "n: " << n << "\n";
input_iterator it(cin);
for(int i = 0; i < n ; ++i){

    l = *(it++);
    cout << "l: " << l << "\n";
    std::vector<int> queue;
    int counter = 0;
    while( counter < l && it != input_iterator() ){
        queue.push_back(*(it++));
        ++counter;
    }
    cout<< "Queue: ";
    std::copy(queue.begin(), queue.end(), 
                  std::ostream_iterator<int>(std::cout, " "));
    cout << "\n";
}