Использование цикла while (!….eof())
в C ++ прервано, потому что цикл никогда не завершится, когда поток перейдет в состояние ошибки!
Скорее, вы должны проверить состояние потока напрямую. Адаптированный к вашему коду, это может выглядеть так:
while (getline(streamOfText, readTextLine)) {
cout << readTextLine << endl;
}
Однако у вас уже есть поток . Зачем помещать его в поток строк? Или вам нужно делать это построчно по какой-либо причине?
Вы можете напрямую инициализировать ваш вектор с помощью входных итераторов. Нет необходимости создавать поток строк и не нужно использовать алгоритм copy
, потому что есть соответствующая перегрузка конструктора.
vector<string> vec((istream_iterator<string>(cin)), istream_iterator<string>());
Обратите внимание на дополнительные скобки вокруг первого аргумента, которые необходимы для устранения неоднозначности этого в объявлении функции.
РЕДАКТИРОВАТЬ Небольшое объяснение, что делает этот код:
C ++ предлагает унифицированный способ указания диапазонов . Диапазон - это просто набор типизированных значений, не вдаваясь в подробности о том, как эти значения хранятся. В C ++ эти диапазоны обозначаются как полуоткрытые интервалы [a
, b
[. Это означает, что диапазон ограничивается двумя итераторами (которые похожи на указатели, но более общие; указатели - это особый вид итератора). Первый итератор, a
, указывает на первый элемент диапазона. Второй, b
, указывает позади последнего элемента. Почему сзади? Потому что это позволяет очень легко перебирать элементы:
for (Iterator i = a; i != b; ++i)
cout << *i;
Как и указатели, итераторы разыменовываются , применяя к ним *
. Это возвращает их значение.
Контейнерные классы в C ++ (например, vector
, list
) имеют специальный конструктор, который позволяет легко копировать значения из другого диапазона в новый контейнер. Следовательно, этот конструктор ожидает двух итераторов. Например, следующий код копирует массив стиля C в вектор:
int values[3] = { 1, 2, 3 };
vector<int> v(values, values + 3);
Здесь values
является синонимом &values[0]
, что означает, что он указывает на первый элемент массива. values + 3
, благодаря арифметике указателей, почти эквивалентен &values[3]
(но это недопустимо C ++!) И указывает на виртуальный элемент позади массив.
Теперь мой код выше делает то же самое, что и в последнем примере. Единственное отличие - это тип итератора, который я использую. Вместо использования простого указателя я использую специальный класс итераторов, предоставляемый C ++. Этот класс итератора оборачивает входной поток таким образом, что ++
продвигает входной поток и *
читает следующий элемент из потока. Тип элемента определяется аргументом типа (следовательно, string
в данном случае).
Чтобы это работало как диапазон, нам нужно указать начало и конец. Увы, мы не знаем конец ввода (это логично, так как конец потока может действительно перемещаться со временем, когда пользователь вводит больше данных в консоль!). Поэтому, чтобы создать виртуальный итератор end , мы не передаем аргумент конструктору istream_iterator
. И наоборот, чтобы создать начальный итератор, мы передаем входной поток. Затем создается итератор, который указывает на текущую позицию в потоке (здесь cin
).
Мой код выше функционально эквивалентен следующему:
istream_iterator<string> front(cin);
istream_iterator<string> back;
vector<string> vec;
for (istream_iterator<string> i = front; i != back; ++i)
vec.push_back(*i);
и это, в свою очередь, эквивалентно использованию следующего цикла:
string word;
while (cin >> word)
vec.push_back(word);