» » » » Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

На нашем литературном портале можно бесплатно читать книгу Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп, Бьёрн Страуструп . Жанр: Программирование. Онлайн библиотека дает возможность прочитать весь текст и даже без регистрации и СМС подтверждения на нашем литературном портале litmir.org.
Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп
Название: Программирование. Принципы и практика использования C++ Исправленное издание
Дата добавления: 22 август 2024
Количество просмотров: 99
Читать онлайн

Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних просмотр данного контента СТРОГО ЗАПРЕЩЕН! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту readbookfedya@gmail.com для удаления материала

Программирование. Принципы и практика использования C++ Исправленное издание читать книгу онлайн

Программирование. Принципы и практика использования C++ Исправленное издание - читать бесплатно онлайн , автор Бьёрн Страуструп

Специальное издание самой читаемой и содержащей наиболее достоверные сведения книги по C++. Книга написана Бьярне Страуструпом — автором языка программирования C++ — и является каноническим изложением возможностей этого языка.
Помимо подробного описания собственно языка, на страницах книги вы найдете доказавшие свою эффективность подходы к решению разнообразных задач проектирования и программирования. Многочисленные примеры демонстрируют как хороший стиль программирования на С-совместимом ядре C++, так и современный -ориентированный подход к созданию программных продуктов. Третье издание бестселлера было существенно переработано автором. Результатом этой переработки стала большая доступность книги для новичков. В то же время, текст обогатился сведениями и методиками программирования, которые могут оказаться полезными даже для многоопытных специалистов по C++. Не обойдены вниманием и нововведения языка: стандартная библиотека шаблонов (STL), пространства имен (namespaces), механизм идентификации типов во время выполнения (RTTI), явные приведения типов (cast-операторы) и другие.
Настоящее специальное издание отличается от третьего добавлением двух новых приложений (посвященных локализации и безопасной обработке исключений средствами стандартной библиотеки), довольно многочисленными уточнениями в остальном тексте, а также исправлением множества опечаток.
Книга адресована программистам, использующим в своей повседневной работе C++. Она также будет полезна преподавателям, студентам и всем, кто хочет ознакомиться с описанием языка «из первых рук».

Перейти на страницу:
<< "World!n"

В стандартной библиотеке есть тип ostream_iterator, предназначенный для работы с потоком вывода; ostream_iterator<T> — это итератор, который можно использовать для записи значений типа T.

В стандартной библиотеке есть также тип istream_iterator<T> для чтения значений типа T.

istream_iterator<string> ii(cin);  // чтение *ii — это чтение строки

                                   // из cin

string s1 = *ii;                   // т.е. cin>>s1

++ii;                              // "готов к вводу следующего

                                   // элемента"

string s2 = *ii; // т.е. cin>>s2

Используя итераторы ostream_iterator и istream_iterator, можно вводить и выводить данные с помощью алгоритма copy(). Например, словарь, сделанный наспех, можно сформировать следующим образом:

int main()

{

  string from, to;

  cin >> from >> to;         // вводим имена исходного

                             // и целевого файлов

  ifstream is(from.c_str()); // открываем поток ввода

  ofstream os(to.c_str());   // открываем поток вывода

  istream_iterator<string> ii(is); // создаем итератор ввода

                                   // из потока

  istream_iterator<string> eos;    // сигнальная метка ввода

  ostream_iterator<string> oo(os,"n"); // создаем итератор

                                        // вывода в поток

  vector<string> b(ii,eos);             // b — вектор, который

                                        // инициализируется

                                        // данными из потока ввода

  sort(b.begin(),b.end());              // сортировка буфера

  copy(b.begin(),b.end(),oo);           // буфер копирования для вывода

}

Итератор eos — это сигнальная метка, означающая “конец ввода.” Когда поток istream достигает конца ввода (который часто называется eof), его итератор istream_iterator становится равным итератору istream_iterator, который задается по умолчанию и называется eos.

 

 Обратите внимание на то, что мы инициализируем объект класса vector парой итераторов. Пара итераторов (a,b), инициализирующая контейнер, означает следующее: “Считать последовательность [a:b] в контейнер”. Естественно, для этого мы использовали пару итераторов (ii,eos) — начало и конец ввода. Это позволяет нам не использовать явно оператор >> и функцию push_back(). Мы настоятельно не рекомендуем использовать альтернативный вариант.

vector<string> b(max_size); // не пытайтесь угадать объем входных

                            // данных

copy(ii,eos,b.begin());

Люди, пытающиеся угадать максимальный размер ввода, обычно недооценивают его, переполняют буфер и создают серьезные проблемы как для себя, так и для пользователей. Переполнение буфера может также создать опасность для сохранности данных.

ПОПРОБУЙТЕ

Приведите программу в рабочее состояние и протестируйте ее на небольшом файле, скажем, содержащем несколько сотен слов. Затем испытайте “настоятельно не рекомендованную версию”, в которой объем входных данных угадывается, и посмотрите, что произойдет при переполнении буфера ввода b. Обратите внимание на то, что наихудшим сценарием является тот, в котором вы не замечаете ничего плохого и передаете программу пользователям.

В нашей маленькой программе мы считываем слова, а затем упорядочиваем их. Пока все, что мы делаем, кажется очевидным, но почему мы записываем слова в “неправильные” ячейки, так что потом вынуждены их сортировать? Кроме того, что еще хуже, оказывается, что мы записываем слова и выводим их на печать столько раз, сколько они появляются в потоке ввода.

Последнюю проблему можно решить, используя алгоритм unique_copy() вместо алгоритма copy(). Функция unique_copy() просто не копирует повторяющиеся идентичные значения. Например, при вызове обычной функции copy() программы введет строку

the man bit the dog

и выведет на экран слова

bit

dog

man

the

the

Если же используем алгоритм unique_copy(), то программа выведет следующие слова:

bit

dog

man

the

 

 Откуда взялись переходы на новую строку? Вывод с разделителями настолько распространен, что конструктор класса ostream_iterator позволяет вам (при необходимости) указывать строку, которая может быть выведена после каждого значения.

ostream_iterator<string> oo(os,"n"); // создает итератор для

                                      // потока вывода

Очевидно, что переход на новую строку — это распространенный выбор для вывода, позволяющий людям легче разбираться в результатах, но, возможно, вы предпочли бы использовать пробелы? Мы могли бы написать следующий код:

ostream_iterator<string> oo(os," ");  // создает итератор для потока

                                      // вывода

В этом случае результаты вывода выглядели бы так:

bit dog man the

21.7.3. Использование класса set для поддержания порядка

Существует еще более простой способ получить такой вывод: использовать контейнер set, а не vector.

int main()

{

  string from, to;

  cin >> from >> to;          // имена исходного и целевого файлов

  ifstream is(from.c_str());  // создаем поток ввода

  ofstream os(to.c_str());    // создаем поток вывода

  istream_iterator<string> ii(is);     // создаем итератор ввода

                                       // из потока

  istream_iterator<string> eos;        // сигнальная метка для ввода

  ostream_iterator<string> oo(os," "); // создаем итератор

                                       // вывода в поток

  set<string> b(ii,eos);      // b — вектор, который инициализируется

                              // данными из потока ввода

  copy(b.begin(),b.end(),oo); // копируем буфер в поток вывода

}

 

 Когда мы вставляем значение в контейнер set, дубликаты игнорируются. Более того, элементы контейнера set хранятся в требуемом порядке. Если в вашем распоряжении есть правильные инструменты, то большинство задач можно решить без труда.

21.7.4. Алгоритм copy_if()

Алгоритм copy() выполняет копирование без каких-либо условий. Алгоритм unique_copy() отбрасывает повторяющиеся соседние элементы, имеющие одинаковые значения. Третий алгоритм копирует только элементы, для которых заданный предикат является истинным.

template<class In,class Out,class Pred>

Out copy_if(In first,In last,Out res,Pred p)

  // копирует элементы, удовлетворяющие предикату

{

  while (first!=last) {

    if (p(*first)) *res++ = *first;

    ++first;

  }

  return res;

}

Используя наш объект-функцию Larger_than из раздела 21.4, можем найти все элементы последовательности, которые больше шести.

void f(const vector<int>& v)

  // копируем все элементы, которые больше шести

{

  vector<int> v2(v.size());

  copy_if(v.begin(),v.end(),v2.begin(),Larger_than(6));

  // ...

}

 

 Из-за моей ошибки этот алгоритм выпал из стандарта 1998 ISO Standard. В настоящее время эта ошибка исправлена, но до сих пор встречаются реализации языка С++, в которых нет алгоритма copy_if. В таком случае просто воспользуйтесь определением, данным в
Перейти на страницу:
Комментариев (0)