Использование istream_iterator для чтения строк

Я не совсем понимаю, чем чтение строки через итераторы отличается от чтения напрямую. В качестве примера рассмотрим код ниже:

#include <iostream>
#include <string>
#include <iterator>

using namespace std;

int main() 
{
    string str{istream_iterator<char>(cin),{}};
    cout << str << endl;

    string str1;
    cin >> str1;
    cout << str1 << endl;
}

Очевидно, что он делает, он читает str, используя istream_iterator, и читает str1 традиционным методом. У меня есть 2 вопроса:

  1. Единственный способ завершить чтение с помощью строковых итераторов — отправить CTRL+D (Unix), что также завершает программу, поэтому вторая часть не выполняется. Есть ли способ обойти это?
  2. При чтении с помощью итераторов не имеет значения, ввожу ли я пробелы (пробел, \t, \n), итератор продолжает читать. Почему это поведение отличается от того, что происходит при чтении напрямую через cin >>?

person vsoftco    schedule 06.08.2014    source источник
comment
попробуйте это на С++ 03 string str{istream_iterator<char>(cin),{}};   -  person vsoftco    schedule 06.08.2014
comment
ах, мой плохой, я уже слишком привык к инициализации фигурных скобок   -  person TemplateRex    schedule 06.08.2014
comment
@TemplateRex не беспокойтесь :) Я просто использовал специфические функции С++ 11, поэтому тег. Конечно вопрос не про C++11   -  person vsoftco    schedule 06.08.2014


Ответы (2)


Я не совсем понимаю, чем чтение строки через итераторы отличается от чтения напрямую.

Разница в вашем примере в том, что первый читает весь поток, а второй читает одно слово (до первого пробела).

В более общем смысле итераторы можно использовать для заполнения других контейнеров (например, используя istream_iterator<int> для заполнения vector<int>) или передавать непосредственно алгоритмам, которые работают с прямыми итераторами.

Единственный способ завершить чтение с помощью строковых итераторов — отправить CTRL+D (Unix), что также завершает работу программы.

Он не завершает программу, он просто закрывает входной поток. Но после этого вы больше ничего не сможете прочитать из ввода; в нынешнем виде ваша программа не имеет смысла, поскольку она пытается читать дальше конца cin.

При чтении с помощью итераторов не имеет значения, ввожу ли я пробелы (пробел, \t, \n), итератор продолжает читать. Почему это поведение отличается от того, что происходит при чтении напрямую через cin >>?

Потому что именно так >> определено для работы со строками.

person Mike Seymour    schedule 06.08.2014
comment
Спасибо, получил вторую часть. Однако я не могу остановить чтение через итераторы. CTRL+D завершает работу, CTRL+Z просто останавливает процесс (UNIX) - person vsoftco; 06.08.2014
comment
@vsoftco: Извините, я ошибся, вы хотите CRTL-D. Но после этого вы не сможете читать из ввода, так как ввода больше нет. - person Mike Seymour; 06.08.2014
comment
Майк: Хорошо, так что в основном использование итераторов для создания/вставки элементов в string через cin — это просто плохая идея... Но есть ли хоть какой-то способ не выйти из программы после CTRL+D? Я пробовал cin.ignore и cin.reset безуспешно. - person vsoftco; 06.08.2014
comment
@vsoftco: Это хорошая идея, если вы хотите использовать весь поток, и плохая идея, если вы хотите сделать что-то еще. - person Mike Seymour; 06.08.2014
comment
Да, я вижу, спасибо. Опять же единственное, чего я до сих пор не знаю, это как продолжить программу после CTRL+D - person vsoftco; 06.08.2014
comment
@vsoftco: CTRL-D не закрывает программу, а просто закрывает входной поток. Ваша программа завершает работу, потому что она выполняется до конца main после закрытия входного потока; cin >> str немедленно возвращается, потому что cin больше недействителен. Он может делать все, что не связано с чтением из cin. - person Mike Seymour; 06.08.2014

  1. Если вы дошли до конца потока, читать больше нечего.

  2. Конечный итератор, предоставленный в конструкторе диапазона, представляет конец ввода. Когда встречается недопустимый символ или конец потока (найден EOF), начальный итератор будет равен итератору конца, и на этом он останавливается. Потоковые итераторы отбрасывают пробелы, поэтому, если вы печатаете свою строку, она не должна содержать пробелов.

    Второе извлечение отформатировано с использованием пробелов для разграничения ввода, поэтому считывается только одно слово.

person 0x499602D2    schedule 06.08.2014
comment
Я также использовал cin.clear(); cin.ignore(); между чтениями, но все еще не могу остановиться после получения CTRL+D. Понял вторую часть, но не могу заставить его прекратить чтение через итераторы без выхода/остановки программы. - person vsoftco; 06.08.2014
comment
@vsoftco Я думал, вы используете итераторы буфера потока, а не итераторы потока. Вы можете ввести пробел, но он все равно будет отброшен. - person 0x499602D2; 06.08.2014
comment
cin.clear() не будет повторно открывать входной поток после его закрытия. При первом чтении поглощается весь поток, поэтому после этого читать нечего. - person Mike Seymour; 06.08.2014