<< *(qr.file->begin() + num) << endl;
return os;
}
Для отчета о количестве найденных соответствий используем функцию size() набора, на который ссылается qr.lines. Поскольку этот набор контролируется указателем shared_ptr, следует помнить об обращении к значению lines. Чтобы вывести слово time или times, в зависимости от того, равен ли размер 1, используем функцию make_plural() (см. раздел 6.3.2).
Цикл for перебирает набор, на который ссылается lines. Тело цикла for выводит номер строки, откорректированный так, как привычно человеку. Числа в наборе являются индексами элементов в векторе, их нумерация начинается с нуля. Но большинство пользователей привыкли к тому, что первая строка имеет номер 1, поэтому будем систематически добавлять 1 к номерам строк, чтобы отображать их в общепринятой форме.
Используем номер строки для выбора строк из вектора, на который указывает указатель-член file. Помните, что при добавлении числа к итератору будет получен элемент на столько же элементов далее (см. раздел 3.4.2). Таким образом, часть file->begin() + num дает номер элемента от начала вектора, на который указывает file.
Обратите внимание: эта функция правильно обрабатывает случай, когда слово не найдено. В данном случае набор будет пуст. Первый оператор вывода заметит, что слово встретилось нуль раз. Поскольку *res.lines пуст, цикл for не выполнится ни разу.
Упражнение 12.30. Определите собственные версии классов TextQuery и QueryResult, а также выполните функцию runQueries() из раздела 12.3.1.
Упражнение 12.31. Что будет, если для хранения номеров строк использовать вектор вместо набора? Какой подход лучше? Почему?
Упражнение 12.32. Перепишите классы TextQuery и QueryResult так, чтобы для хранения входного файла вместо вектора vector использовался класс StrBlob.
Упражнение 12.33. В главе 15 программа запроса будет дополнена, и классу QueryResult понадобятся дополнительные члены. Добавьте функции-члены по имени begin() и end(), возвращающие итераторы для набора номеров строк, возвращенных данным запросом, и функцию-член get_file(), возвращающую указатель shared_ptr на файл в объекте QueryResult.
Резюме
В языке С++ для резервирования памяти используется оператор new, а для освобождения — оператор delete. Библиотека определяет также класс allocator, чтобы резервировать пустые блоки динамической памяти.
Резервирующие динамическую память программы отвечают за ее освобождение. Освобождение динамической памяти — богатейший источник ошибок: память может быть не освобождена никогда или может быть освобождена, когда еще есть указатели на нее. Новая библиотека определяет классы интеллектуальных указателей (shared_ptr, unique_ptr и weak_ptr), делающие работу с динамической памятью намного более безопасной. Интеллектуальный указатель автоматически освобождает память, как только удаляется последний указатель на нее. В современных программах С++ следует использовать именно интеллектуальные указатели.
Термины
Деструктор (destructor). Специальная функция-член, которая освобождает занятую объектом память, когда он выходит из области видимости или удаляется.
Динамическая память (free store). Пул памяти, доступный программе для хранения объектов, создаваемых динамически.
Динамически созданный объект (dynamically allocated object). Объект, который создан в динамической памяти. Такие объекты существуют до тех пор, пока не будут удалены из динамической памяти явно или пока программа не завершит работу.
Интеллектуальный указательshared ptr. Интеллектуальный указатель, обеспечивающий совместную собственность: объект освобождается, когда удаляется последний указатель shared_ptr на тот объект.
Интеллектуальный указательunique_ptr. Интеллектуальный указатель, обеспечивающий единоличную собственность: объект освобождается, когда удаляется указатель unique_ptr на этот объект. Указатель unique_ptr не может быть скопирован или присвоен непосредственно.
Интеллектуальный указательweak_ptr. Интеллектуальный указатель на объект, управляемый указателем shared_ptr. Указатель shared_ptr не учитывает указатель weak_ptr, принимая решение об освобождении своего объекта.
Интеллектуальный указатель (smart pointer). Библиотечный тип, действует как указатель, но допускающий проверку на безопасность использования. Тип сам заботится об освобождении памяти, когда это нужно.
Классallocator. Библиотечный класс, резервирующий области памяти.