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

на главную

Жанры

Эффективное использование 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 {

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

Бастард Императора

Орлов Андрей Юрьевич
1. Бастард Императора
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Бастард Императора

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

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

Имя нам Легион. Том 7

Дорничев Дмитрий
7. Меж двух миров
Фантастика:
боевая фантастика
рпг
аниме
5.00
рейтинг книги
Имя нам Легион. Том 7

Измена. Вторая жена мужа

Караева Алсу
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. Вторая жена мужа

Буря империи

Сай Ярослав
6. Медорфенов
Фантастика:
аниме
фэнтези
фантастика: прочее
эпическая фантастика
5.00
рейтинг книги
Буря империи

Пенсия для морского дьявола

Чиркунов Игорь
1. Первый в касте бездны
Фантастика:
попаданцы
5.29
рейтинг книги
Пенсия для морского дьявола

На изломе чувств

Юнина Наталья
Любовные романы:
современные любовные романы
6.83
рейтинг книги
На изломе чувств

Тринадцатый II

NikL
2. Видящий смерть
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Тринадцатый II

Сирота

Шмаков Алексей Семенович
1. Светлая Тьма
Фантастика:
юмористическое фэнтези
городское фэнтези
аниме
5.00
рейтинг книги
Сирота

Законы Рода. Том 9

Flow Ascold
9. Граф Берестьев
Фантастика:
городское фэнтези
попаданцы
аниме
дорама
фэнтези
фантастика: прочее
5.00
рейтинг книги
Законы Рода. Том 9

Красноармеец

Поселягин Владимир Геннадьевич
1. Красноармеец
Фантастика:
боевая фантастика
попаданцы
4.60
рейтинг книги
Красноармеец

Огненный князь 4

Машуков Тимур
4. Багряный восход
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Огненный князь 4

Начальник милиции. Книга 5

Дамиров Рафаэль
5. Начальник милиции
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Начальник милиции. Книга 5

Инкарнатор

Прокофьев Роман Юрьевич
1. Стеллар
Фантастика:
боевая фантастика
рпг
7.30
рейтинг книги
Инкарнатор