//
auto p = alloc.allocate(vi.size() * 2);
//
auto q = uninitialized_copy(vi.begin(), vi.end(), p);
//
uninitialized_fill_n(q, vi.size(), 42);
Подобно алгоритму copy() (см. раздел 10.2.2), алгоритм uninitialized_copy() получает три итератора. Первые два обозначают исходную последовательность, а третий обозначает получателя, в который будут скопированы эти элементы. Итератор назначения, переданный алгоритму uninitialized_copy(), должен обозначить незаполненную память. В отличие от алгоритма copy(), алгоритм uninitialized_copy() создает элементы в своем получателе.
Подобно алгоритму copy(), алгоритм uninitialized_copy() возвращает (приращенный) итератор назначения. Таким образом, вызов функции uninitialized_copy() возвращает указатель на следующий элемент после последнего заполненного. В данном примере этот указатель сохраняется в переменной q, передаваемой функции uninitialized_fill_n(). Эта функция, как и функция fill_n() (см. раздел 10.2.2), получает указатель на получателя, количество и значение. Она создает заданное количество объектов из заданного значения в позиции, начиная с заданной получателем.
Упражнение 12.26. Перепишите программу из начала раздела, используя класс allocator.
Для завершения обсуждения библиотеки реализуем простую программу текстового запроса. Она позволит пользователю искать в заданном файле слова, которые могли встречаться в нем. Результатом запроса будет количество экземпляров слова и список строк, в которых оно присутствует. Если слово встречается несколько раз в той же строке, то она отображается только однажды. Строки отображаются в порядке возрастания, т.е. строка номер 7 отображается перед строкой номер 9 и т.д.
Например, прочитав файл, содержащий начало этой главы и запустив поиск слова element, программа должна создать следующий вывод:
element occurs 112 times
(line 36) A set element contains only a key;
(line 158) operator creates a new element
(line 160) Regardless of whether the element
(line 168) When we fetch an element from a map, we
(line 214) If the element is not found, find returns
Далее следует примерно 100 строк, также содержащих слово element.
Наилучший способ начать проект программы — это составить перечень ее функциональных возможностей. Зная, какие именно функции необходимо обеспечить, значительно легче разобраться, какие именно структуры данных понадобятся. Итак, начнем с требований, которым должна удовлетворять разрабатываемая программа.
• Читая ввод, программа должна запоминать строку (строки), в которой присутствует искомое слово. Следовательно, программа должна читать ввод построчно и разделять прочитанные строки на отдельные слова
• При создании вывода программа должна:
• получать номера строк, содержащих искомое слово;
• нумеровать строки в порядке возрастания без дубликатов;
• отображать текст исходного файла по заданному номеру строки.
Эти требования можно выполнить с помощью библиотечных средств.
• Для хранения копии всего входного файла используем вектор vector. Каждая строка входного файла станет элементом этого вектора. При необходимости вывода строку можно будет выбрать, используя ее номер как индекс.
• Для разделения строки на слова используем строковый поток istringstream (см. раздел 8.3).
• Для хранения номеров строк, в которых присутствует искомое слово, используем контейнер set. Это гарантирует, что каждая строка будет присутствовать только однажды, а номера строки будут храниться в порядке возрастания.
• Для связи каждого слова с набором номеров строк, в которых присутствует искомое слово, используем контейнер map. Это позволит выбрать соответствующий набор для каждого заданного слова.
По рассматриваемым вскоре причинам в решении будет также использован указатель shared_ptr.