Совет 42. Следите за тем, чтобы конструкция less<T> означала operator<
Совет 42. Следите за тем, чтобы конструкция less<T> означала operator<
Допустим, объект класса Widget обладает атрибутами weight и maxSpeed:
class Widget { public:
size_t weight() const;
size_t maxSpeed() const;
}
Будем считать, что естественная сортировка объектов Widget осуществляется по атрибуту weight, что отражено в операторе < класса Widget:
bool operator<(const Widget& Ihs. const Widget& rhs) {
return lhs.weight()<rhs.weight();
}
Предположим, потребовалось создать контейнер multiset<Widget>, в котором объекты Widget отсортированы по атрибуту maxSpeed. Известно, что для контейнера multiset<Widget> используется функция сравнения less<Widget>, которая по умолчанию вызывает функцию operator< класса Widget. Может показаться, что единственный способ сортировки multi set<Widget> по атрибуту maxSpeed основан на разрыве связи между less<Widget> и operator< и специализации less<Widget> на сравнении атрибута maxSpeed:
template<> // Специализация std::less
struct std::less<Widget>; // для Widget: такой подход
public // считается крайне нежелательным!
std::binаry_function<Widget,
Widget,// Базовый класс описан
bool>{// в совете 40
bool operator() (const Widget& Ihs. const Widget& rhs) const
{
return lhs.maxSpeed()<rhs.maxSpeed();
}
};
Поступать подобным образом не рекомендуется, но, возможно, совсем не по тем причинам, о которых вы подумали. Вас не удивляет, что этот фрагмент вообще компилируется? Многие программисты обращают внимание на то, что в приведенном фрагменте специализируется не обычный шаблон, а шаблон из пространства имен std. «Разве пространство std не должно быть местом священным, зарезервированным для разработчиков библиотек и недоступным для простых программистов? — спрашивают они. — Разве компилятор не должен отвергнуть любое вмешательство в творения бессмертных гуру С++?»
Вообще говоря, попытки модификации компонентов 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 преподносит неприятный сюрприз.
Программисты С++ часто опираются на предположения. Например, они предполагают, что копирующие конструкторы действительно копируют,(как показано в совете 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& Ihs.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< Если объекты должны сортироваться по другому критерию, создайте специальный класс функтора и назовите его как-нибудь иначе.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Глава 14 Вы следите за мной, я слежу за вами
Глава 14 Вы следите за мной, я слежу за вами Plpki ytw eai rtc aaspx M llogw qj wef ms rh xq? [78] Через пару дней после встречи с другом отца Марком Касденом, который работал в бюро частных расследований, я отправился в долгий путь обратно в Лас-Вегас, чтобы забрать одежду и личные вещи. Отдел по
IP Operator
IP Operator Программа IP Operator так же, как и предыдущая, предназначена для создания и настройки сетевых профилей. Данным приложением комплектуются ноутбуки производства компании LG. Любой желающий может также бесплатно скачать эту программу с сайта LG. Она не привязывается к
1.6.7. Правило прозрачности: для того чтобы упростить проверку и отладку программы, ее конструкция должна быть обозримой
1.6.7. Правило прозрачности: для того чтобы упростить проверку и отладку программы, ее конструкция должна быть обозримой Поскольку отладка часто занимает три четверти или более времени разработки, раннее окончание работы в целях облегчения отладки может быть очень
Правило 11: В operator= осуществляйте проверку на присваивание самому себе
Правило 11: В operator= осуществляйте проверку на присваивание самому себе Присваивание самому себе возникает примерно в такой ситуации:class Widget {...};Widget w;...w = w; // присваивание себеКод выглядит достаточно нелепо, однако он совершенно корректен, и в том, что программисты на такое
1.6.7. Правило прозрачности: для того чтобы упростить проверку и отладку программы, ее конструкция должна быть обозримой
1.6.7. Правило прозрачности: для того чтобы упростить проверку и отладку программы, ее конструкция должна быть обозримой Поскольку отладка часто занимает три четверти или более времени разработки, раннее окончание работы в целях облегчения отладки может быть очень
Конструкция for-do
Конструкция for-do Синтаксис конструкции for-do для цикла с увеличением значения счетчика:for идентификатор_счетчика := начальное_значение to конечное_эначение do блок_кода;Синтаксис конструкции for-do для цикла с уменьшением значения счетчика:for идентификатор_счетчика :=
Конструкция while-do
Конструкция while-do Синтаксис конструкции while-do: while выражение do блок_кода;Выход из цикла while-do происходит в том случае, если выражение, расположенное между ключевыми словами while и do, дает значение False. Цикл может не выполниться ни одного
Конструкция repeat-until
Конструкция repeat-until Синтаксис конструкции repeat-until: repeat блок_кода until выражение;Выход из цикла repeat-until происходит в том случае, если выражение, расположенное после ключевого слова until, дает значение
Шаг 13 - Перегрузка operator+.
Шаг 13 - Перегрузка operator+. Оператор operator-› мы уже перегружали. Результаты получились просто феерические. Давайте замучаем еще кого-нибудь и посмотрим, что получится? Давайте. Первейшим кандидатом на переопределение является оператор operator+,потому что в жизни (помимо С++) он
Массивы и оператор operator[].
Массивы и оператор operator[]. Давайте попробуем придумать класс, объекты которого вели бы себя как массивы? Поехали. Решим, что класс внутри себя должен иметь для простоты массив, ну там счетчик элементов… вроде больше нечему там быть. Ну раз так, то возьмем стек из Шага 13, для
Совет 21. Следите за тем, чтобы функции сравнения возвращали false в случае равенства
Совет 21. Следите за тем, чтобы функции сравнения возвращали false в случае равенства Сейчас я покажу вам нечто любопытное. Создайте контейнер set с типом сравнения less_equal и вставьте в него число 10:set<int,less_equal<int> > s; // Контейнер s сортируется по критерию "<="s.insert(10); // Вставка
Совет 30. Следите за тем, чтобы приемный интервал имел достаточный размер
Совет 30. Следите за тем, чтобы приемный интервал имел достаточный размер Контейнеры STL автоматически увеличиваются с добавлением новых объектов (функциями insert, push_front, push_back и т. д.). Автоматическое изменение размеров чрезвычайно удобно, и у многих программистов создается
Следите за логами
Следите за логами Изучайте свои логи, чтобы следить за дискуссиямиВам полезно знать, кто о вас говорит. Проверьте свои логи и узнайте, что откуда берется. Кто на вас ссылается? Кто ругается? Какие из блогов, попавшие в списки на Technorati, Blogdex, Feedster, Del.icio.us и Daypop, говорят о
IP Operator
IP Operator Программа IP Operator производства компании LG распространяется с ноутбуками LG и, возможно, с некоторыми другими. Скорее всего, данная программа будет работать и на ноутбуках, произведенных другими компаниями (мы не проверяли). Назначение данной программы такое же, как и