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

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

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

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

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

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

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

Перейти на страницу:
ум. Очевидно, что извлечение информации и заголовков сообщений электронной почты — это детский пример приложения. Значение разделения задач, выделения модулей и поступательного наращивания приложения по мере увеличения масштаба приложения проявляется все более ярко.

Для того чтобы извлечь информацию, мы просто ищем все упоминания ключа "John Doe", используя функцию equal_range() (раздел Б.4.10). Затем перемещаемся по всем элементам в последовательности [first,second], возвращаемой функцией equal_range(), извлекая темы сообщений с помощью функции find_subject().

typedef multimap<string, const Message*>::const_iterator MCI;

pair<MCI,MCI> pp = sender.equal_range("John Doe");

for (MCI p = pp.first; p!=pp.second; ++p)

  cout << find_subject(p–>second) << 'n';

Перемещаясь по элементам объекта класса map, мы получаем последовательность пар (ключ,значение), в которых, как в любом другом объекте класса pair, первый элемент (в данном случае ключ класса stringkey) называется first, а второй (в данном случае объект класса Message) — second (см. раздел 21.6).

23.4.1. Детали реализации

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

Конструктор класса Mail_file открывает файл и создает векторы lines и m.

Mail_file::Mail_file(const string& n)

  // открывает файл с именем "n"

  // считывает строки из файла "n" в вектор lines

  // находит сообщения в векторе lines и помещает их в вектор m,

  // для простоты предполагая, что каждое сообщение заканчивается

  // строкой "––––" line

{

  ifstream in(n.c_str()); // открываем файл

  if (!in) {

    cerr << " нет " << n << 'n';

    exit(1); // прекращаем выполнение программы

}

string s;

  while (getline(in,s)) lines.push_back(s); // создаем вектор

                                            // строк

  Line_iter first = lines.begin(); // создаем вектор сообщений

  for (Line_iter p = lines.begin(); p!=lines.end(); ++p) {

    if (*p == "––––") { // конец сообщения

      m.push_back(Message(first,p));

      first = p+1; // строка –––– не является частью

                   // сообщения

    }

  }

}

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

ПОПРОБУЙТЕ

Что значит “более хорошая обработка ошибок”? Измените конструктор класса Mail_file так, чтобы он реагировал на ошибки форматирования, связанные с использованием строки “––––”.

Функции find_from_addr() и find_subject() не имеют конкретного содержания, пока мы не выясним, как идентифицировать информацию в файле (используя регулярные выражения и из разделов 23.6–23.10).

int is_prefix(const string& s, const string& p)

  // Является ли строка p первой частью строки s?

{

  int n = p.size();

  if (string(s,0,n)==p) return n;

  return 0;

}

bool find_from_addr(const Message* m, string& s)

{

  for(Line_iter p = m–>begin(); p!=m–>end(); ++p)

  if (int n = is_prefix(*p,"From: ")) {

    s = string(*p,n);

    return true;

  }

  return false;

}

string find_subject(const Message* m)

{

  for(Line_iter p = m.begin(); p!=m.end(); ++p)

  if (int n = is_prefix(*p,"Subject: "))

    return string(*p,n);

  return "";

}

 

 Обратите внимание на то, как мы используем подстроки: конструктор string(s,n) создает строку, состоящую из хвоста строки s, начиная с элемента s[n] (т.е. s[n]..s[s.size()–1]), а конструктор string(s,0,n) создает строку, состоящую из символов s[0]..s[n–1]. Поскольку эти операторы на самом деле создают новые строки и копируют символы, они должны использоваться очень осторожно, чтобы не снизить производительность программы.

 

 Почему функции find_from_addr() и find_subject() так отличаются друг от друга? Например, одна из них возвращает переменную типа bool, а другая — объект класса string. Потому что мы хотели подчеркнуть следующие моменты.

• Функция find_from_addr() различает поиск пустой строки адреса ("") и поиск отсутствующей строки адреса. В первом случае функция find_from_addr() возвращает значение true (поскольку она нашла адрес) и присваивает строке s значение "" (потому что адресная строка просто оказалась пустой). Во втором случае она возвращает значение false (поскольку в файле вообще не оказалось адресной строки).

• Функция find_subject() возвращает строку "" и когда строка темы сообщения оказалась пустой, и когда ее вообще нет.

Насколько полезным является такое различие, которое проводит функция find_from_addr()? Необходимо ли это? Мы считаем, что это полезно и необходимо. При поиске информации в файле данных это различие проявляется снова и снова: нашли ли мы искомую строку и содержит ли она то, что нам нужно? В реальной программе обе функции, find_from_addr() и find_subject(), следовало бы написать в стиле функции find_from_addr(), чтобы дать пользователям возможность проводить такое различие.

Эта программа не является оптимальной с точки зрения производительности, но мы надеемся, что в типичных ситуациях она работает достаточно быстро. В частности, она считывает входной файл только один раз и не хранит несколько копий текста из этого файла. Для крупных файлов было бы целесообразно заменить класс multimap классом unordered_multimap, но без испытаний невозможно сказать, насколько это повысит эффективность программы.

Введение в стандартные ассоциативные контейнеры (map, multimap, set, unordered_map и unordered_multimap) см. в разделе 21.6.

23.5. Проблема

Потоки ввода-вывода и класс string помогают нам считывать и записывать последовательности символов, хранить их и выполнять над ними основные операции. Однако при работе с текстом во многих случаях необходимо анализировать контекст строки или рассматривать много аналогичных строк. Рассмотрим тривиальный пример. Возьмем сообщение электронной почты (последовательность слов) и посмотрим, содержит ли оно аббревиатуру U.S. и почтовый код (две буквы, за которыми следуют пять цифр).

string s;

while (cin>>s) {

  if (s.size()==7

  && isalpha(s[0]) && isalpha(s[1])

  && isdigit(s[2]) && isdigit(s[3]) && isdigit(s[4])

  && isdigit(s[5]) && isdigit(s[6]))

  cout << " найдена " << s << 'n';

}

Здесь значение isalpha(x) равно true, если x — это буква, а

Перейти на страницу:
Комментариев (0)