Вход/Регистрация
Эффективное использование STL
вернуться

Мейерс Скотт

Шрифт:

for_each(vw.begin, vw.end, ptr_fun(test)); // Компилируется и работает,

// как вариант 1.

Если вы забываете, когда функция

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

Существует и другой подход — использовать

ptr_fun
в случае крайней необходимости. Если функция отсутствует там, где необходимы определения типов, компилятор выдает сообщение об ошибке. Тогда вы возвращаетесь к программе и включаете в нее пропущенный вызов.

С

mem_fun
и
mem_fun_ref
ситуация принципиально иная. Эти функции всегда должны применяться при передаче функции компонентам STL, поскольку помимо определения типов (необходимых или нет) они адаптируют синтаксис вызова, который обычно используется для функций класса, к синтаксису, принятому в STL. Если не использовать эти функции при передаче указателей на функции класса, программа не будет компилироваться.

Остается лишь разобраться со странными именами адаптеров. Перед нами самый настоящий пережиток прошлого STL. Когда впервые возникла необходимость в адаптерах, разработчики STL ориентировались на контейнеры указателей (с учетом недостатков таких контейнеров, описанных в советах 7, 20 и 33, это может показаться странным, но не стоит забывать, что контейнеры указателей поддерживают полиморфизм, а контейнеры объектов — нет). Когда понадобился адаптер для функций классов (MEMber FUNctions), его назвали

mem_fun
. Только позднее разработчики поняли, что для контейнеров объектов понадобится другой адаптер, и для этой цели изобрели имя
mem_fun_ref
. Конечно, выглядит не слишком элегантно, но… бывает, ничего не поделаешь. Пусть тот, кому никогда не приходилось жалеть о поспешном выборе имен своих компонентов, первым бросит камень.

Совет 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& lhs, const Widget& rhs) {

 return lhs.weight<rhs.weight;

}

Предположим, потребовалось создать контейнер

multiset<Widget>
, в котором объекты
Widget
отсортированы по атрибуту
maxSpeed
. Известно, что для контейнера
multiset<Widget>
используется функция сравнения
less<Widget>
, которая по умолчанию вызывает функцию
operator<
класса
Widget
. Может показаться, что единственный способ сортировки
multiset<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& lhs, const Widget& rhs) const {

return lhs.maxSpeed < rhs.maxSpeed;

 }

};

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

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

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

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

  • Читать дальше
  • 1
  • ...
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

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