| Алгоритм | Функция контейнера | |||
|---|---|---|---|---|
| Что вы хотите узнать | Несортированный интервал | Сортированный интервал | Для set и map | Для multiset и multimap |
| Присутствует ли заданное значение? | find | binary_search | count | find |
| Присутствует ли заданное значение? И если присутствует, то где находится первый объект с этим значением? | find | equal_range | find | find или lower_bound (см. ранее) |
| Где находится первый объект со значением, не предшествующим заданному? | find_if | lower_bound | lower_bound | lower_bound |
| Где находится первый объект со значением, следующим после заданного? | find_if | upper_bound | upper_bound | upper_bound |
| Сколько объектов имеют заданное значение? | count | equal_range | count | count |
| Где находятся все объекты с заданным значением? | equal_range | equal_range | equal_range | find (итеративный вызов) |
Несколько странно выгладит частое присутствие equal_range в столбце, относящемся к сортированным интервалам. Оно связано с особой ролью проверки эквивалентности при поиске. Использование lower_bound и upper_bound чревато ошибочной проверкой равенства, а при использовании equal_range более естественно выглядит проверка эквивалентности. Во второй строке предпочтение отдается equal_range еще по одной причине: equal_range работает с логарифмическим временем, а вызов find связан с линейными затратами времени.
Для контейнеров multiset и multimap в качестве возможных кандидатов для поиска первого объекта с заданным значением указаны два алгоритма, find и lower_bound. Обычно для решения этой задачи выбирается find — возможно, вы обратили внимание, что именно этот алгоритм указан в таблице для контейнеров set и map. Однако multi-контейнеры не гарантируют, что при наличии нескольких элементов с заданным значением find найдет lower_bound и выполните вручную вторую часть проверки эквивалентности, описанной в совете 19 (без этой проверки можно обойтись при помощи equal_range, но вызов equal_range обходится дороже, чем вызов lower_bound).
Выбрать между count, find, binary_search, lower_bound, upper_bound и equal_range несложно. Предпочтение отдается тому алгоритму или функции, которые обладают нужными возможностями, обеспечивают нужное быстродействие и требуют минимальных усилий при вызове. Следуйте этой рекомендации (или обращайтесь к таблице), и у вас никогда не будет проблем с выбором.
Совет 46. Передавайте алгоритмам объекты функций вместо функций
Часто говорят, что повышение уровня абстракции языков высокого уровня приводит к снижению эффективности сгенерированного кода. Александр Степанов, изобретатель STL, однажды разработал небольшой комплекс тестов для оценки «платы за абстракцию» при переходе с C на C++. В частности, результаты этих тестов показали, что код, сгенерированный для работы с классом, содержащим double, почти всегда уступает по эффективности соответствующему коду, непосредственно работающему с double. С учетом сказанного вас может удивить тот факт, что передача алгоритмам объектов функций STL — то есть объектов, маскирующихся под функции, — обычно обеспечивает
Предположим, вы хотите отсортировать вектор чисел типа double по убыванию. Простейшее решение этой задачи средствами STL основано на использовании алгоритма sort с объектом функции типа greater:
vector
…
sort(v.begin, v.end, greater
Вспомнив о «плате за абстракцию», программист решает заменить объект функции «настоящей» функцией, которая к тому же оформлена как подставляемая (inline):
inline bool doubleGreater(double d1, double d2) {
return d1 > d2;
}
…
sort(v.begin, v.end, doubleGreater);