2016-11-18 8 views
2

я получаю следующий вход со стандартного ввода:istream_iterator потребляет слишком много из потока

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

Первая строка представляет число очередей (назовем это значение n). Затем для каждой очереди в первой строке есть значение l, которое обозначает длину очереди, за которой следует фактическая очередь.

Я пытаюсь поставить очереди в вектор с помощью istream_iterator следующим образом:

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"; 
} 

Этот код производит следующий вывод:

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

Как вы можете видеть первую очередь для чтения правильно. Но второй l должен быть 5, а не 2.

Что происходит с 5? Он потребляется итератором? Где я сделал ошибку?

+0

Пройдите через код, построчно, в отладчике. И прекратите затенять переменные, используйте другое имя для итератора во внутреннем цикле. Кроме того, есть ли причина, по которой вы хотите использовать итератор ввода, чем простой цикл, в котором вы получаете значения, используя простой 'std :: cin >> ...'? –

+0

Это и вся теневая вещь на самом деле ошибка, которая произошла, написав этот пример. Я исправил это – user2393256

ответ

2

Ваша проблема в том, что ваш for-loop оставляет i в позиции рядом с последним элементом очереди. Поэтому при вызове operator>> для получения следующего значения для l, вы являетесь одним из шагов «чтения» слишком далеко.

Чтобы избежать этой проблемы, вы можете использовать один и тот же итератор для всех операций чтения - и переименовать его, чтобы избежать столкновения с именем во внешнем контуре переменной i, например:

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"; 
} 
2

IANALL, но istream_iterator, насколько мне известно, позволяет читать дальше в своем operator++(). Поскольку вы заново создаете итератор istream для каждой группы (строки чисел), которую вы читаете, вы отбрасываете итератор, который уже прочитал следующее целое число из входного потока.

Одним из решений было бы создать входной итератор только один раз за пределами вашего цикла и использовать его повсюду.

2

for цикл в основном просто причудливый цикл while.

Давайте этот for цикл из кода:

for (input_iterator it(cin); counter < l && it != input_iterator(); ++i){ 
    queue.push_back((*it)); 
    ++counter; 
} 

Это эквивалентно следующему:

{ 
    input_iterator it(cin); 
    while (counter < l && it != input_iterator()) 
    { 
     queue.push_back((*it)); 
     ++counter; 
     ++it; 
    } 
} 

Обратите внимание, что последняя строку в цикле, в ++it; заявление? Это, что вызывает вашу проблему. Это увеличит итератор, если слишком много, поэтому после цикла итератор прочитал 5 на входе. Следующая операция ввода после цикла будет затем читать 2 в следующей строке.

Одним из решений является сохранение итератора и повторное использование его во внешнем контуре. Возможно использовать его для все вход.

Другим решением, которое я намекал на мой комментарий, чтобы иметь for цикл от нуля до lтолько и не использовать итератор на всех, но только простой cin >> ....