double* high2 = high(middle, &v[0]+v.size()); // максимум второй
// половины
// ...
Здесь указатель high1
ссылается на максимальный элемент первой половины вектора, а указатель high2
— на максимальный элемент второй половины. Графически это можно изобразить следующим образом:
В качестве аргументов функции high()
мы использовали указатели. Этот механизм управления памятью относится к слишком низкому уровню и уязвим для ошибок. Мы подозреваем, что большинство программистов для поиска максимального элемента в векторе написали бы нечто вроде следующего:
double* find_highest(vector
{
double h = –1;
double* high = 0;
for (int i=0; i
if (h
{
high = &v[i];
h = v[i];
}
return high;
}
Однако это не обеспечивает достаточно гибкости, которую мы “случайно” уже придали функции high()
, — мы не можем использовать функцию find_highest()
для поиска наибольшего элемента в части вектора. На самом деле, “связавшись с указателями”, мы достигли практической выгоды, получив функцию, которая может работать как с векторами, так и с массивами. Помните: обобщение может привести к функциям, которые позволяют решать больше задач.
20.2. Принципы библиотеки STL
Стандартная библиотека языка С++, обеспечивающая основу для работы с данными, представленными в виде последовательности элементов, называется STL. Обычно эту аббревиатуру расшифровывают как “стандартная библиотека шаблонов” (“standard template library”). Библиотека STL является частью стандарта ISO C++. Она содержит контейнеры (такие как классы vector
, list
и map
) и обобщенные алгоритмы (такие как sort
, find
и accumulate
). Следовательно, мы имеем право говорить, что такие инструменты, как класс vector
, являются как частью библиотеки STL, так и стандартной библиотеки. Другие средства стандартной библиотеки, такие как потоки ostream
(см. главу 10) и функции для работы строками в стиле языка С (раздел B.10.3), не являются частью библиотеки STL. Чтобы лучше оценить и понять библиотеку STL, сначала рассмотрим проблемы, которые мы должны устранить, работая с данными, а также обсудить идеи их решения.
if
, циклах, функциях, обработке ошибок и пр. В других случаях мы фокусируемся на данных и говорим о массивах, векторах, строках, файлах и пр. Однако, для того чтобы выполнить полезную работу, мы должны учитывать оба аспекта. Большой объем данных невозможно понять без анализа, визуализации и поиска “чего-нибудь интересного”. И наоборот, мы можем выполнять вычисления так, как хотим, но такой подход оказывается слишком скучным и “стерильным”, пока мы не получим некие данные, которые свяжут наши вычисления с реальностью. Более того, вычислительная часть программы должна элегантно взаимодействовать с “информационной частью.
Говоря так о данных, мы подразумеваем много разных данных: десятки фигур, сотни значений температуры, тысячи регистрационных записей, миллионы точек, миллиарды веб-страниц и т.д.; иначе говоря, мы говорим о работе с контейнерами данных потоками данных и т.д. В частности, мы не рассматриваем вопросы, как лучше выбрать набор данных, представляющих небольшой объект, такой как комплексное число, запись о температуре или окружность. Эти типы описаны в главах 9, 11 и 14.
Рассмотрим простые примеры, которые иллюстрируют наше понятие о крупном наборе данных.
• Сортировка слов в словаре.
• Поиск номера в телефонной книге по заданному имени.
• Поиск максимальной температуры.
• Поиск всех чисел, превышающих 8800.
• Поиск первого появления числа 17.
• Сортировка телеметрических записей по номерам устройств.
• Сортировка телеметрических записей по временным меткам.
• Поиск первого значения, большего, чем строка “Petersen”.
• Поиск наибольшего объема.
• Поиск первого несовпадения между двумя последовательностями.
• Вычисление попарного произведения элементов двух последовательностей.
• Поиск наибольшей месячной температуры.
• Поиск первых десяти лучших продавцов по записям о продажах.
• Подсчет количества появлений слова “Stroustrup” в сети веб.
• Вычисление суммы элементов.
Обратите внимание на то, что каждую из этих задач мы можем описать, не упоминая о способе хранения данных. Очевидно, что мы как-то должны работать со списками, векторами, файлами, потоками ввода и т.д., но мы не обязаны знать, как именно хранятся (и собираются) данные, чтобы говорить о том, что будем делать с ними. Важен лишь тип значений или объектов (тип элементов), способ доступа к этим значениям или объектам, а также что именно мы хотим с ними сделать.