Программирование >>  Включение нужных заголовков 

1 ... 48 49 50 [ 51 ] 52 53 54 ... 71


return lhs.maxSpeecl()<rhs.maxSpeed();

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

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

namespace std{

tempiate<typename Т> Специализация std::less

struct less<boost::shared ptr<T> >: для boost::shared ptr<T>

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

bi nary functi on<boost:;shared ptr<T>.

boost::shared ptr<T>. Базовый класс описан bool>{ в совете 40

bool operatorO (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 преподносит неприятный сюрприз.

Программисты С++ часто опираются на предположения. Например, они предполагают, что копирующие конструкторы действительно копируют,(как показано в совете 8, невыполнение этого правила приводит к удивительным последствиям). Они предполагают, что в результате взятия адреса объекта вы получаете указатель на этот объект (в совете 18 рассказано, что может произойти в противном случае). Они предполагают, что адаптеры bi ndlst и 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 operatorO(const WidgetS Ihs.const WidgetS rhs) const {

return 1 hs.maxSpeed()<rhs.maxSpeed():

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

multi set<Wi dget,MaxSpeedCompa re> wi dgets;

Смысл этой команды абсолютно очевиден: мы создаем контейнер 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. Используйте алгоритмы вместо циклов

Каждому алгоритму передается по крайней мере одна пара итераторов, определяющих интервал объектов для выполнения некоторой операции. Так, алгоритм miп е1 ement находит минимальное значение в интервале, алгоритм accumulate вычисляет сводную величину, характеризующую интервал в целом (см. совет 37), а алгоритм partition делит элементы интервала на удовлетворяющие и не удовлетворяющие заданному критерию (см. совет 31). Чтобы алгоритм мог выполнить свою задачу, он должен проанализировать каждый объект в переданном интервале (или интервалах), для чего объекты в цикле перебираются от начала интервала к концу. Некоторые алгоритмы (такие как f i nd и f i ndi f) могут вернуть управление



1 ... 48 49 50 [ 51 ] 52 53 54 ... 71

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика