int main()
{
vector
copy(istream_iterator
back_inserter(l));
5. Чтобы увидеть, прошло ли преобразование правильно, выведем на экран содержимое списка. Форматирование ввода/вывода, left << setw(15) <<
for (const auto &[name, pop, lat, lon] : l) {
cout << left << setw(15) << name
<< " population=" << pop
<< " lat=" << lat
<< " lon=" << lon << '\n';
}
}
6. Текстовый файл, из которого наша программа будет считывать данные, выглядит следующим образом. В нем содержится информация о четырех городах: их названия, количество населения и географические координаты:
Braunschweig
250000 52.268874 10.526770
Berlin
4000000 52.520007 13.404954
New York City
8406000 40.712784 -74.005941
Mexico City
8851000 19.432608 -99.133208
7. Компиляция и запуск программы дадут следующий результат, он соответствует нашим ожиданиям. Попробуйте изменить входной файл, добавляя ненужные пробелы перед названием городов, чтобы увидеть, как они будут отфильтрованы:
$ cat cities.txt | ./initialize_complex_objects
Braunschweig population=250000 lat=52.2689 lon=10.5268
Berlin population=4000000 lat=52.52 lon=13.405
New York City population=8406000 lat=40.7128 lon=-74.0059
Mexico City population=8851000 lat=19.4326 lon=-99.1332
Как это работает
Мы снова рассмотрели короткий пример. В нем мы лишь создали новую структуру city
>>
итератора std::istream
для данного типа. Это позволило десериализовать элементы типа city
, полученные из стандартного потока ввода, с помощью istream_iterator
.Открытым может оставаться вопрос, связанный с проверкой на ошибки. Поэтому снова рассмотрим реализацию оператора >>
istream& operator>>(istream &is, city &c)
{
is >> ws;
getline(is, c.name);
is >> c.population >> c.latitude >> c.longitude;
return is;
}
Мы считываем множество разных элементов. Что произойдет, если один из них даст сбой, а следующий за ним — нет? Означает ли это потенциальное считывание всех следующих элементов со «смещением» в потоке токенов? Нет, этого не произойдет. Если хотя бы один элемент потока ввода не сможет быть преобразован, то объект потока ввода входит в ошибочное состояние и отказывается выполнять дальнейшие преобразования. Это значит, что если, например, c.population
c.latitude
не могут быть преобразованы, то остальные операнды >>
будут просто отброшены и мы покинем область действия функции оператора с наполовину заполненным объектом.На вызывающей стороне мы получим оповещение об этом при написании конструкции if (input_stream >> city_object)
false
, если объект потока ввода находится в ошибочном состоянии. Зная это, можно сбросить поток и выполнить подходящие операции.В данном примере мы не писали подобных условий if
std::istream_iterator
. Реализация перегруженной версии оператора ++
для этого итератора также выполняет проверку ошибок во время преобразования. При генерации ошибок преобразование будет приостановлено. В этом состоянии проверка будет возвращать значение true
при сравнении с конечным итератором, что заставляет алгоритм copy завершить работу. Таким образом, мы в безопасности. Заполняем контейнеры с применением итераторов std::istream
В предыдущем примере вы узнали, как можно собрать сложные структуры из потока ввода, а затем заполнить списки или векторы полученными элементами.
В этот раз мы усложним задачу, заполняя на основе стандартного потока ввода контейнер std::map