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

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

Жанры

Стандарты программирования на С++. 101 правило и рекомендация

Александреску Андрей

Шрифт:

deque<double>::iterator current = d.begin;

for (size_t i =0; i < max; ++i) {

 // Сохраняем current действительным

 current = d.insert(current, data[i] + 41);

 ++current; // Увеличиваем его, когда это

} // становится безопасным

Вызов алгоритма позволяет легко обойти все ловушки в этом коде:

transform(

 data.begin, data.end, // Копируем элементы

 data inserter(d, d.begin), //
в d с начала контейнера,

 bind2nd(plus<double>,41)); // добавляя к каждому 41

Впрочем,

bind2nd
и
plus
достаточно неудобны. Откровенно говоря, в действительности их мало кто использует, и связано это в первую очередь с плохой удобочитаемостью такого кода (см. рекомендацию 6).

При использовании лямбда-функций, генерирующих для нас функциональные объекты, мы можем написать совсем простой код:

transform(data, data+max, inserter(d,d.begin), _1 + 41);

Пример 2. Найти первый элемент между

x
и
у
. Рассмотрим простой цикл, который выполняет поиск в
vector<int> v
первого элемента, значение которого находится между
x
и
y
. Он вычисляет итератор, который указывает либо на найденный элемент, либо на
v.end
:

vector<int>::iterator i = v.begin;

for (; i != v.end; ++i)

 if (*i > x && *i < y) break;

Вызов алгоритма достаточно проблематичен. При отсутствии лямбда-функций у нас есть два варианта — написание собственного функционального объекта или использование стандартных связывателей. Увы, в последнем случае мы не можем обойтись только стандартными связывателями и должны использовать нестандартный (хотя и достаточно распространенный) адаптер

compose2
, но даже в этом случае код получается совершенно непонятным, так что такой код на практике никто просто не напишет:

vector<int>::iterator i =

 find_if(v.begin, v.end,

 compose2(logical_and<bool>,

 bind2nd(greater<int>, x), bind2nd(less<int>, y)));

Другой вариант, а именно — написание собственного функционального объекта — достаточно жизнеспособен. Он достаточно хорошо выглядит в точке вызова, а главный его недостаток— необходимость написания функционального объекта

BetweenValues
, который визуально удаляет логику из точки вызова:

template<typename T>

class BetweenValues : public unary_function<T, bool> {

public:

 BetweenValues(const T& low, const T& high)

: low_(low), high_(high) { }

 bool operator(const T& val) const

{ return val > low_ && val < high_; }

private:

 T low_, high_;

};

vector<int>::iterator i =

 find_if( v.begin, v.end, BetweenValues<int>(x, y));

При

применении лямбда-функций можно написать просто:

vector<int>::iterator i =

 find_if(v.begin, v.end, _1 > x && _1 < y);

Исключения

При использовании функциональных объектов тело цикла оказывается размещено в некотором месте, удаленном от точки вызова, что затрудняет чтение исходного текста. (Использование простых объектов со стандартными и нестандартными связывателями представляется нереалистичным.)

Лямбда-функции [Boost] решают проблему и надежно работают на современных компиляторах, но они не годятся для более старых компиляторов и могут выдавать большие запутанные сообщения об ошибках при некорректном использовании. Вызов же именованных функций, включая функции-члены, все равно требует синтаксиса с использованием связывателей.

Ссылки

[Allison98] §15 • [Austern99] §11-13 • [Boost] Lambda library • [McConnell93] §15 • [Meyers01] §43 • [Musser01] §11 • [Stroustrup00] §6.1.8, §18.5.1 • [Sutter00] §7

85. Пользуйтесь правильным алгоритмом поиска

Резюме

Данная рекомендация применима к поиску определенного значения в диапазоне. При поиске в неотсортированном диапазоне используйте алгоритмы

find
/
find_if
или
count
/
count_if
. Для поиска в отсортированном диапазоне выберите
lower_bound
,
upper_bound
,
equal_range
или (реже)
binary_search
. (Вопреки своему имени,
binary_search
обычно — неверный выбор.)

Обсуждение

В случае неотсортированных диапазонов,

find
/
find_if
и
count
/
count_if
могут за линейное время определить, находится ли данный элемент в диапазоне, и если да, то где именно. Заметим, что алгоритмы
find
/
find_if
обычно более эффективны, поскольку могут завершить поиск, как только искомый элемент оказывается найден.

В случае сортированных диапазонов лучше использовать алгоритмы бинарного поиска —

binary_search, lower_bound
,
upper_bound
и
equal_range
, которые имеют логарифмическое время работы. Увы, несмотря на свое красивое имя,
binary_search
практически всегда бесполезен, поскольку возвращает всего лишь значение
типа
bool, указывающее, найден искомый элемент или нет. Обычно вам требуется алгоритм
lower_bound
или
upper_bound
, или
equal_range
, который выдает результаты обоих алгоритмов — и
lower_bound
, и
upper_bound
(и требует в два раза больше времени).

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

Черный маг императора 3

Герда Александр
3. Черный маг императора
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Черный маг императора 3

Повелитель механического легиона. Том VIII

Лисицин Евгений
8. Повелитель механического легиона
Фантастика:
технофэнтези
аниме
фэнтези
5.00
рейтинг книги
Повелитель механического легиона. Том VIII

Пипец Котенку! 3

Майерс Александр
3. РОС: Пипец Котенку!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Пипец Котенку! 3

Разбуди меня

Рам Янка
7. Серьёзные мальчики в форме
Любовные романы:
современные любовные романы
остросюжетные любовные романы
5.00
рейтинг книги
Разбуди меня

Боги, пиво и дурак. Том 6

Горина Юлия Николаевна
6. Боги, пиво и дурак
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Боги, пиво и дурак. Том 6

Болотник 2

Панченко Андрей Алексеевич
2. Болотник
Фантастика:
попаданцы
альтернативная история
6.25
рейтинг книги
Болотник 2

Ты всё ещё моя

Тодорова Елена
4. Под запретом
Любовные романы:
современные любовные романы
7.00
рейтинг книги
Ты всё ещё моя

S-T-I-K-S. Пройти через туман

Елисеев Алексей Станиславович
Вселенная S-T-I-K-S
Фантастика:
боевая фантастика
7.00
рейтинг книги
S-T-I-K-S. Пройти через туман

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

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

Сводный гад

Рам Янка
2. Самбисты
Любовные романы:
современные любовные романы
эро литература
5.00
рейтинг книги
Сводный гад

Я князь. Книга XVIII

Дрейк Сириус
18. Дорогой барон!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я князь. Книга XVIII

Королевская Академия Магии. Неестественный Отбор

Самсонова Наталья
Любовные романы:
любовно-фантастические романы
8.22
рейтинг книги
Королевская Академия Магии. Неестественный Отбор

Последняя Арена 6

Греков Сергей
6. Последняя Арена
Фантастика:
рпг
постапокалипсис
5.00
рейтинг книги
Последняя Арена 6

Жребий некроманта. Надежда рода

Решетов Евгений Валерьевич
1. Жребий некроманта
Фантастика:
фэнтези
попаданцы
6.50
рейтинг книги
Жребий некроманта. Надежда рода