Чтение онлайн

на главную - закладки

Жанры

Эффективное использование STL
Шрифт:

return lhs.maxSpeed < rhs.maxSpeed;

 }

};

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

std
. «Разве пространство
std
не должно быть местом священным, зарезервированным для разработчиков библиотек и недоступным для простых программистов? — спрашивают они. — Разве компилятор не должен отвергнуть любое вмешательство в творения бессмертных гуру C++?»

Вообще говоря, попытки модификации компонентов

std
действительно запрещены, поскольку их последствия могут оказаться непредсказуемыми, но в некоторых ситуациях минимальные изменения все же разрешены. А именно, программистам разрешается специализировать шаблоны
std
для пользовательских типов. Почти всегда существуют альтернативные решения, но в отдельных случаях такой подход вполне разумен. Например, разработчики классов умных указателей часто хотят, чтобы их классы при сортировке вели себя как встроенные указатели, поэтому специализация
std::less
для типов умных указателей встречается не так уж редко. Далее приведен фрагмент класса
shared_ptr
из библиотеки
Boost
, упоминающегося в советах 7 и 50:

namespace std {

 template<typename T> // Специализация std::less

 struct less<boost::shared_ptr<T> >: // для boost::shared_ptr<T>

 public // (boost - пространство имен)

 binary_function<boost::shared_ptr<T>,

boost::shared_ptr<T>, // Базовый класс описан

bool> { // в совете 40

bool operator(const boost::shared_ptr<T>& a,

const boost::shared_ptr<T>& b) const {

return less<T*>(a.get, b.get); // shared_ptr::get возвращает

} // встроенный указатель

 }; // из объекта shared_ptr

}

В данном примере специализация выглядит вполне разумно, поскольку специализация

less
всего лишь гарантирует, что порядок сортировки умных указателей будет совпадать с порядком сортировки их встроенных аналогов. К сожалению, наша специализация less для класса
Widget
преподносит неприятный сюрприз.

Программисты C++ часто опираются на предположения. Например, они предполагают, что копирующие конструкторы действительно копируют (как показано в совете 8, невыполнение этого правила приводит к удивительным последствиям). Они предполагают, что в результате взятия адреса объекта вы получаете указатель на этот объект (в совете 18 рассказано, что может произойти в противном случае). Они предполагают, что адаптеры

bind1st
и
not2
могут применяться к объектам функций (см. совет 40). Они предполагают, что оператор
+
выполняет сложение (кроме объектов
string
, но знак «+» традиционно используется для выполнения конкатенации строк), что оператор
вычитает, а оператор
==
проверяет равенство. И еще они предполагают, что функция
less
эквивалентна
operator<
.

В действительности

operator<
представляет собой нечто большее, чем реализацию
less
по умолчанию — он соответствует ожидаемому поведению
less
. Если
less
вместо вызова
operator<
делает что-либо другое, это нарушает ожидания программистов и вступает в противоречие с «принципом минимального удивления». Конечно, поступать так не стоит — особенно если без этого можно обойтись.

В STL нет ни одного случая использования

less
, когда программисту бы не предоставлялась возможность задать другой критерий сравнения. Вернемся к исходному примеру с контейнером
multiset<Widget>
, упорядоченному по атрибуту
maxSpeed
. Задача решается просто: для выполнения нужного сравнения достаточно
создать класс функтора практически с любым именем, кроме
less
. Пример:

struct MaxSpeedCompare:

 public binary_function<Widget, Widget, bool> {

 bool operator(const Widget& lhs, const Widget& rhs) const {

return lhs.maxSpeed < rhs.maxSpeed;

 }

};

При создании контейнера

multiset
достаточно указать тип сравнения
MaxSpeedCompare
, тем самым переопределяя тип сравнения по умолчанию (
less<Widget>
):

multiset<Widget, MaxSpeedCompare> widgets;

Смысл этой команды абсолютно очевиден: мы создаем контейнер

multiset
с элементами
Widget
, упорядоченными в соответствии с классом функтора
MaxSpeedCompare
. Сравните со следующим объявлением:

multiset<Widget> widgets;

В нем создается контейнер

multiset
объектов
Widget
, упорядоченных по стандартному критерию. Строго говоря, упорядочение производится по критерию
less<Widget>
, но большинство программистов будет полагать, что сортировка производится функцией
operator<
. Не нужно обманывать их ожидания и подменять определение
less
. Если вы хотите использовать
less
(явно или косвенно), проследите за тем, чтобы этот критерий был эквивалентен
operator<
. Если объекты должны сортироваться по другому критерию, создайте специальный класс функтора и назовите его как-нибудь иначе.

Программирование в STL

STL традиционно характеризуется как совокупность контейнеров, итераторов, алгоритмов и объектов функций, однако программирование в STL заключает в себе нечто большее. Этот термин означает, что программист способен правильно выбирать между циклами, алгоритмами или функциями контейнеров; знает, в каких случаях

equal_range
предпочтительнее
lower_bound
, когда
lower_bound
предпочтительнее
find
и когда
find
превосходит
equal_range
. Термин означает, что программист умеет повышать быстродействие алгоритма посредством замены функций эквивалентными функторами и избегает написания непереносимого или плохо читаемого кода. Более того, к этому понятию даже относится умение читать сообщения об ошибках компилятора, состоящие из нескольких тысяч символов, и хорошее знание Интернет-ресурсов, посвященных STL (документация, расширения и даже полные реализации).

Да, для программирования в STL необходимо много знать, и большая часть этой информации приведена в данной главе.

Совет 43. Используйте алгоритмы вместо циклов

Каждому алгоритму передается по крайней мере одна пара итераторов, определяющих интервал объектов для выполнения некоторой операции. Так, алгоритм

min_element
находит минимальное значение в интервале, алгоритм
accumulate
вычисляет сводную величину, характеризующую интервал в целом (см. совет 37), а алгоритм
partition
делит элементы интервала на удовлетворяющие и не удовлетворяющие заданному критерию (см. совет 31). Чтобы алгоритм мог выполнить свою задачу, он должен проанализировать каждый объект в переданном интервале (или интервалах), для чего объекты в цикле перебираются от начала интервала к концу. Некоторые алгоритмы (такие как
find
и
find_if
) могут вернуть управление до завершения полного перебора, но и в этих алгоритмах задействован внутренний цикл. Ведь даже алгоритмы
find
и
find_if
должны проанализировать все элементы интервала, прежде чем принять решение об отсутствии искомого элемента.

Поделиться:
Популярные книги

Как я строил магическую империю 4

Зубов Константин
4. Как я строил магическую империю
Фантастика:
боевая фантастика
постапокалипсис
аниме
фантастика: прочее
фэнтези
5.00
рейтинг книги
Как я строил магическую империю 4

Безумный Макс. Поручик Империи

Ланцов Михаил Алексеевич
1. Безумный Макс
Фантастика:
героическая фантастика
альтернативная история
7.64
рейтинг книги
Безумный Макс. Поручик Империи

Попаданка 3

Ахминеева Нина
3. Двойная звезда
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Попаданка 3

Муж на сдачу

Зика Натаэль
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Муж на сдачу

Призыватель нулевого ранга. Том 3

Дубов Дмитрий
3. Эпоха Гардара
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Призыватель нулевого ранга. Том 3

На границе империй. Том 10. Часть 5

INDIGO
23. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 10. Часть 5

Адвокат

Константинов Андрей Дмитриевич
1. Бандитский Петербург
Детективы:
боевики
8.00
рейтинг книги
Адвокат

На границе империй. Том 7

INDIGO
7. Фортуна дама переменчивая
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
6.75
рейтинг книги
На границе империй. Том 7

Здравствуй, 1985-й

Иванов Дмитрий
2. Девяностые
Фантастика:
альтернативная история
5.25
рейтинг книги
Здравствуй, 1985-й

О, Путник!

Арбеков Александр Анатольевич
1. Квинтет. Миры
Фантастика:
социально-философская фантастика
5.00
рейтинг книги
О, Путник!

Чужбина

Седой Василий
2. Дворянская кровь
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Чужбина

Бестужев. Служба Государевой Безопасности. Книга четвертая

Измайлов Сергей
4. Граф Бестужев
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бестужев. Служба Государевой Безопасности. Книга четвертая

Локки 5. Потомок бога

Решетов Евгений Валерьевич
5. Локки
Фантастика:
юмористическое фэнтези
аниме
фэнтези
5.00
рейтинг книги
Локки 5. Потомок бога

На границе империй. Том 10. Часть 4

INDIGO
Вселенная EVE Online
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
5.00
рейтинг книги
На границе империй. Том 10. Часть 4