1
votes

I am new to C++, sorry if this is a silly question. I cannot seem to figure out why this does not work. It copies into the first vector, and seems to skip past the second copy call.

#include <iostream>
#include <vector>
#include <iterator>

using namespace std;

int main ()
{
    vector<int> first;
    vector<int> second;

    copy(istream_iterator<int>(cin),istream_iterator<int>(),back_inserter(first));
    cin.clear();
    copy(istream_iterator<int>(cin),istream_iterator<int>(),back_inserter(second)); 
    return 0;
}

I want to use the copy function to read istream_iterator input into any number of vectors(one call to copy per vector). In other words: I want to be able to enter "1 2 3 4 5 ctrl+d" into the console and have 1,2,3,4,5 entered into the first vector. Then enter "6 7 8 9 10 ctrl+d" into the console and have 6,7,8,9,10 entered into the second vector.

The problem is that after I enter some input into the first vector and press control+d the istream_iterator for cin remains equal to istream_iterator(), regardless of cin's fail state. This causes every subsequent call to "copy" to fail (because istream_iteratorcin is already equal to istream_iterator() which the program interprets as eof). So my question is: What do I need to do to "reset" the iterator along with the cin stream? cin.clear() is indeed clearing all the fail bits. However the istream_iterator(cin) is still equal to istream_iterator() regardless. From what I understand, istream_iterators that are bound to a stream should only be equal to the default istream_iterator value when the stream is in a fail state. What am I missing?

1
Define How it should work and what is not working. - Alok Save
I am trying to enter some numbers into stdin and have those ints copied into the first vector until I press ctrl-d at which point the first copy will stop. Then I want to clear the fail state of stdin and repeat the process of copying numbers into the second vector. The problem is that it copies into the first but does not copy into the second because somehow the istream_iterator<int>(cin) remains equal to istream_iterator<int>(). I thought that clearing the fail state and recalling istream_iterator<int>(cin) would give me fresh iterator that is not equal to the default istream_iterator value. - Kaleetos
Cannot reproduce on my end. I input the first set of values, ^D, input the second set of values, ^D, program terminates with correct ouput (I'm dumping the vector elements to check). - Luc Danton
Luc, really?? You are using the exact same code and it works for you?? - Kaleetos
This is what my program looks like and what I input (with a ^D after each line). Ideone only pass the whole of input in one go so it all ends up in the first vector and is not representative of what I'm doing. - Luc Danton

1 Answers

3
votes

The istream_iterator is an input iterator, which means you can only dereference each iterator value once. You are literally reading from a stream, and there's no seeking or going back. So once you hit the end-of-stream, there's nothing more to input and the second range is empty.

Why not just say vector<int> second(first); to make a copy?


Update: After you clarified the question, here's a new answer: You're misunderstanding how stdin works. There is only one input. Ctrl-D isn't anything inherent to C++; rather, it is a convention of your platform, and your platform will terminate the input buffer when you signal Ctrl-D. After that, the input "file" is finished, and no further data can be written to it.

Your approach is a bit unorthodox, though. Usually, you would just read line by line, separated by Enter, and tokenize each line. Using string streams, you get very similar code:

std::string line;
std::vector<int> first, second;

// Read line 1
if (std::getline(std::cin, line))
{
  std::istringstream iss(line);
  std::copy(std::istream_iterator<int>(iss), std::istream_iterator<int>(), std::back_inserter(first));
}
else { /* error */ }

// Read line 2
if (std::getline(std::cin, line))
{
  std::istringstream iss(line);
  std::copy(std::istream_iterator<int>(iss), std::istream_iterator<int>(), std::back_inserter(second));
}
else { /* error */ }