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

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

Жанры

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

list<Widget*> lpw; // См. ранее

for_each(lpw.begin, lpw.end,

 mem_fun(&Widget::test)); // Теперь нормально компилируется

При вызове

for_each
передается объект типа
mem_fun_t
, содержащий указатель на
Widget::test
. Для каждого указателя
Widget*
в
lpw
алгоритм
for_each
«вызывает» объект
mem_fun_t
с использованием синтаксиса 1, а этот объект непосредственно вызывает
Widget::test
для указателя
Widget*
с использованием синтаксиса 3.

В целом

mem_fun
приводит синтаксис 3, необходимый для
Widget::test
при использовании с указателем
Widget*
, к синтаксису 1, используемому алгоритмом
for_each
. По вполне понятным причинам такие классы, как
mem_fun_t
, называются адаптерами объектов функций. Наверное, вы уже догадались, что по аналогии со всем, о чем говорилось ранее, функции
mem_fun_ref
адаптируют синтаксис 2 к синтаксису 1 и генерируют адаптеры типа
mem_fun_ref_t
.

Объекты, создаваемые функциями

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

for_each(vw.begin, vw.end, test); // См. ранее, вариант 1.

// Нормально компилируется

компилируется, а следующие конструкции не компилируются:

for_each(vw.begin, vw.end, &Widget::test); // См. ранее, вариант 2.

// Не компилируется.

for_each(lpw.begin, lpw.end, &Widget::test); // См. ранее, вариант 3.

// Не компилируется

При первом вызове (вариант 1) передается настоящая функция, поэтому адаптация синтаксиса вызова для

for_each
не нужна; алгоритм сам вызовет ее с правильным синтаксисом. Более того,
for_each
не использует определения типов, добавляемые функцией
ptr_fun
, поэтому при передаче
test
функция
ptr_fun
не нужна. С другой стороны, добавленные определения не повредят, поэтому следующий фрагмент функционально эквивалентен приведенному выше:

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 {

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

Проходные дворы

Хруцкий Эдуард Анатольевич
Документальная литература:
прочая документальная литература
6.25
рейтинг книги
Проходные дворы

Deus vult

Рокотов Алексей
3. Путь князя
Фантастика:
фэнтези
рпг
попаданцы
5.00
рейтинг книги
Deus vult

Звездная Кровь. Экзарх VII

Рокотов Алексей
7. Экзарх
Фантастика:
боевая фантастика
рпг
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Звездная Кровь. Экзарх VII

Гримуар темного лорда VI

Грехов Тимофей
6. Гримуар темного лорда
Фантастика:
попаданцы
аниме
фэнтези
5.25
рейтинг книги
Гримуар темного лорда VI

Восхитительная ведьма

Джейн Анна
1. Восхитительная ведьма
Любовные романы:
современные любовные романы
4.67
рейтинг книги
Восхитительная ведьма

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

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

Менталист. Конфронтация

Еслер Андрей
2. Выиграть у времени
Фантастика:
боевая фантастика
6.90
рейтинг книги
Менталист. Конфронтация

Последний Паладин. Том 8

Саваровский Роман
8. Путь Паладина
Фантастика:
боевая фантастика
попаданцы
5.00
рейтинг книги
Последний Паладин. Том 8

Земля под ногами. Из истории заселения и освоения Эрец Исраэль. 1918-1948. Книга 2

Кандель Феликс Соломонович
Научно-образовательная:
история
5.00
рейтинг книги
Земля под ногами. Из истории заселения и освоения Эрец Исраэль. 1918-1948. Книга 2

Большие дела

Ромов Дмитрий
7. Цеховик
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Большие дела

Воронцов. Перезагрузка

Тарасов Ник
1. Воронцов. Перезагрузка
Фантастика:
попаданцы
альтернативная история
фантастика: прочее
5.00
рейтинг книги
Воронцов. Перезагрузка

Черный Маг Императора 16

Герда Александр
16. Черный маг императора
Фантастика:
юмористическое фэнтези
аниме
фэнтези
фантастика: прочее
попаданцы
5.00
рейтинг книги
Черный Маг Императора 16

Евреи России. Времена и события. История евреев Российской империи

Кандель Феликс Соломонович
Научно-образовательная:
история
5.00
рейтинг книги
Евреи России. Времена и события. История евреев Российской империи

Мир в латах (сборник)

Полякова Татьяна Викторовна
Фантастика:
социально-философская фантастика
научная фантастика
5.00
рейтинг книги
Мир в латах (сборник)