- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп
Шрифт:
Интервал:
Закладка:
larger_than_v);
if (p!=v.end()) { /* мы нашли значение, превышающее 31 */ }
v_val = x; // устанавливаем переменную v_val равной x
// для следующего вызова предиката larger_than_v
list<double>::iterator q = find_if(v.begin(), v.end(),
larger_than_v);
if (q!=v.end()) { /* мы нашли значение, превышающее x*/ }
// ...
}
Какая гадость! Мы убеждены, что люди, написавшие такую программу, в конце концов получат по заслугам, но мы заранее сочувствуем пользователям и любому человеку, который столкнется с этим кодом. Повторим: должен быть более удобный способ!
ПОПРОБУЙТЕ
Почему такое использование переменной v вызывает у нас такое отвращение? Назовите по крайней мере три способа, которые приведут к непонятным ошибкам. Назовите три приложения, в которых такие программы особенно недопустимы.
21.4. Объекты-функции
Итак, мы хотим передавать предикат алгоритму find_if() и чтобы этот предикат сравнивал элементы со значением, которое мы зададим как его аргумент. В частности, мы хотим написать примерно такой код:
void f(list<double>& v, int x)
{
list<double>::iterator p = find_if(v.begin(), v.end(),
Larger_than(31));
if (p!=v.end()) { /* мы нашли число, превышающее 31 */ }
list<double>::iterator q = find_if(v.begin(), v.end(),
Larger_than(x));
if (q!=v.end()) { /* мы нашли число, превышающее x */ }
// ...
}
Очевидно, что функция Larger_than должна удовлетворять двум условиям.
• Ее можно вызывать как предикат, например pred(*first).
• Она может хранить значение, например 31 или x, передаваемое при вызове.
Для того чтобы выполнить эти условия, нам нужен объект-функция, т.е. объект, который ведет себя как функция. Нам нужен объект, поскольку именно объекты могут хранить данные, например значение для сравнения. Рассмотрим пример.
class Larger_than {
int v;
public:
Larger_than(int vv) : v(vv) { } // хранит аргумент
bool operator()(int x) const { return x>v; } // сравнение
};
Следует отметить, что это определение представляет собой именно то, что мы требовали от предиката. Теперь осталось понять, как это работает. Написав выражение Larger_than(31), мы (очевидно) создаем объект класса Larger_than, хранящий число 31 в члене v. Рассмотрим пример.
find_if(v.begin(),v.end(),Larger_than(31))
Здесь мы передаем объект Larger_than(31) алгоритму find_if() как параметр с именем pred. Для каждого элемента v алгоритм find_if() осуществляет вызов
pred(*first)
Это активизирует оператор вызова функции, т.е. функцию-член operator(), для объекта-функции с аргументом *first. В результате происходит сравнение значения элемента, т.е. *first, с числом 31.
Мы видим, что вызов функции можно рассматривать как результат работы оператора (), аналогично любому другому оператору. Оператор () называют также оператором вызова функции (function call operator) или прикладным оператором (application operator). Итак, оператор () в выражении pred(*first) эквивалентен оператору Larger_than::operator(), точно так же, как оператор [] в выражении v[i] эквивалентен оператору vector::operator[].
21.4.1. Абстрактная точка зрения на функции-объекты
Таким образом, мы имеем механизм, позволяющий функции хранить данные, которые ей нужны. Очевидно, что функции-объекты образуют универсальный, мощный и удобный механизм. Рассмотрим понятие объекта-функции подробнее.
class F { // абстрактный пример объекта-функции
S s; // состояние
public:
F(const S& ss):s(ss) { /* устанавливает начальное значение */ }
T operator() (const S& ss) const
{
// делает что-то с аргументом ss
// возвращает значение типа T (часто T — это void,
// bool или S)
}
const S& state() const { return s; } // демонстрирует
// состояние
void reset(const S& ss) { s = ss; } // восстанавливает
// состояние
};
Объект класса F хранит данные в своем члене s. По мере необходимости объект-функция может иметь много данных-членов. Иногда вместо фразы “что-то хранит данные” говорят “нечто пребывает в состоянии”. Когда мы создаем объект класса F, мы можем инициализировать это состояние. При необходимости мы можем прочитать это состояние. В классе F для считывания состояния предусмотрена операция state(), а для записи состояния — операция reset(). Однако при разработке объекта-функции мы свободны в выборе способа доступа к его состоянию.
Разумеется, мы можем прямо или косвенно вызывать объект-функцию, используя обычную систему обозначений. При вызове объект-функция F получает один аргумент, но мы можем определять объекты-функции, получающие столько параметров, сколько потребуется.
Использование объектов-функций является основным способом параметризации в библиотеке STL. Мы используем объекты-функции для того, чтобы указать алгоритму поиска, что именно мы ищем (см. раздел 21.3), для определения критериев сортировки (раздел 21.4.2), для указания арифметических операций в численных алгоритмах (раздел 21.5), для того, чтобы указать, какие объекты мы считаем равными (раздел 21.8), а также для многого другого. Использование объектов-функций — основной источник гибкости и универсальности алгоритмов.
Объекты-функции, как правило, очень эффективны. В частности, передача по значению небольшого объекта-функции в качестве аргумента шаблонной функции обеспечивает оптимальную производительность. Причина проста, но удивительна для людей, хорошо знающих механизм передачи функций в качестве аргументов: обычно передача функции в виде объекта приводит к созданию значительно более маленького и быстродействующего кода, чем при передаче функции как таковой! Это утверждение оказывается истинным, только если объект мал (например, если он содержит одно-два слова данных или вообще не хранит данные) или передается по ссылке, а также если оператор вызова функции невелик (например, простое сравнение с помощью оператора <) и определен как подставляемая функция (например, если его определение содержится в теле класса). Большинство примеров в этой главе — и в книге в целом — соответствует этому правилу. Основная причина высокой производительности небольших и простых объектов-функций состоит в том, что они предоставляют компилятору объем информации о типе, достаточный для того, чтобы сгенерировать оптимальный код. Даже устаревшие компиляторы с несложными оптимизаторами могут генерировать простую машинную инструкцию “больше” для сравнения в классе Larger_than, вместо вызова функции. Вызов функции обычно выполняется в 10–50 раз дольше, чем

