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

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

Жанры

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

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

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

<x, y>
. В цикле это делается так:

vector<int> v;

int х, у;

vector<int>::iterator i=v.begin; // Перебирать элементы,
начиная

for(; i!=v.end; ++i){ // с v.begin, до нахождения нужного

 if(*i > x && *i < y)) break; // элемента или достижения v.end

}

… // После завершения цикла

// i указывает на искомый элемент

// или совпадает с v.end

То же самое можно сделать и при помощи

find_if
, но для этого придется воспользоваться нестандартным адаптером объекта функции — например,
compose2
из реализации SGI (см. совет 50):

vector<int>::iterator i =

 find_if(v.begin, v.end, // Найти первое значение val,

 compose2(logical_and<bool>, // для которого одновременно

 bind2nd(greater<int>, x), // истинны условия

 bind2nd(less<int>, y))); // val>x, и val<y

Но даже если бы нестандартные компоненты не использовались, многие программисты полагают, что вызов алгоритма значительно уступает циклу по наглядности, и я склонен с ними согласиться (см. совет 47).

Вызов

find_if
можно было бы упростить за счет выделения логики проверки в отдельный класс функтора.

template<typename T>

class BetweenValues:

 public unary_function<T, bool> { // См. совет 40

public:

 BetweenValues(const T& lowValue, const T& highValue) :

lowVal(lowValue), highVal(highValue) {}

 bool operator(const T& val) const {

return val > lowVal && val < highVal;

 }

private:

 T lowVal;

 T highVal;

};

vector<int> iterator i = find_if(v.begin, v.end,

 BetweenValues<int>(x, y));

Однако у такого решения имеются свои недостатки. Во-первых, создание шаблона

BetweenValues
требует значительно большей работы, чем простое написание тела цикла. Достаточно посчитать строки в программе: тело цикла — одна строка,
BetweenValues
— четырнадцать строк. Соотношение явно не в пользу алгоритма. Во-вторых, описание критерия поиска физически отделяется от вызова. Чтобы понять смысл
вызова
find_if
, необходимо найти определение
BetweenValues
, но оно должно располагаться вне функции, содержащей вызов
find_if
. Попытка объявить
BetweenValues
внутри функции, содержащей вызов
find_if
:

{ // Начало функции

 …

 template<typename T>

 class BetweenValues: public unary_function<T, bool> {…};

 vector<int>::iterator i = find_if(v.begin, v.end,

BetweenValues<int>(x, у));

} // Конец функции

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

BetweenValues
в виде класса:

{ // Начало функции

 …

 class BetweenValues: public unary_function<int, bool> {…};

 vector<int>::iterator i = find_if(v.begin, v.end,

BetweenValues(x, y));

} // Конец функции

все равно ничего не получается, поскольку классы, определяемые внутри функций, являются локальными, а локальные классы не могут передаваться в качестве аргументов шаблонов (как функтор, передаваемый

find_if
). Печально, но классы функторов и шаблоны классов функторов не разрешается определять внутри функций, как бы удобно это ни было.

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

for_each
) так, чтобы полученный код был более наглядным и прямолинейным.

Если вы согласны с тем, что вызовы алгоритмов обычно предпочтительнее циклов, а также с тем, что интервальные функции обычно предпочтительнее циклического вызова одноэлементных функций (см, совет 5), можно сделать интересный вывод: хорошо спроектированная программа C++, использующая STL, содержит гораздо меньше циклических конструкций, чем аналогичная программа, не использующая STL, и это хорошо. Замена низкоуровневых конструкций

for
,
while
и
do
высокоуровневыми терминами
insert
,
find
и
foreach
повышает уровень абстракции и упрощает программирование, документирование, усовершенствование и сопровождение программы.

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

Моя на одну ночь

Тоцка Тала
Любовные романы:
современные любовные романы
короткие любовные романы
5.50
рейтинг книги
Моя на одну ночь

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

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

Измена. Отбор для предателя

Лаврова Алиса
1. Отбор для предателя
Фантастика:
фэнтези
5.00
рейтинг книги
Измена. Отбор для предателя

Кодекс Крови. Книга II

Борзых М.
2. РОС: Кодекс Крови
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Крови. Книга II

Шаг в бездну

Муравьёв Константин Николаевич
3. Перешагнуть пропасть
Фантастика:
фэнтези
космическая фантастика
7.89
рейтинг книги
Шаг в бездну

Часовая битва

Щерба Наталья Васильевна
6. Часодеи
Детские:
детская фантастика
9.38
рейтинг книги
Часовая битва

Вечная Война. Книга II

Винокуров Юрий
2. Вечная война.
Фантастика:
юмористическая фантастика
космическая фантастика
8.37
рейтинг книги
Вечная Война. Книга II

Хроники странного королевства. Вторжение. (Дилогия)

Панкеева Оксана Петровна
110. В одном томе
Фантастика:
фэнтези
9.38
рейтинг книги
Хроники странного королевства. Вторжение. (Дилогия)

Часовой ключ

Щерба Наталья Васильевна
1. Часодеи
Фантастика:
фэнтези
9.36
рейтинг книги
Часовой ключ

Инвестиго, из медика в маги

Рэд Илья
1. Инвестиго
Фантастика:
фэнтези
городское фэнтези
попаданцы
5.00
рейтинг книги
Инвестиго, из медика в маги

Кротовский, может, хватит?

Парсиев Дмитрий
3. РОС: Изнанка Империи
Фантастика:
попаданцы
альтернативная история
аниме
7.50
рейтинг книги
Кротовский, может, хватит?

Драконий подарок

Суббота Светлана
1. Королевская академия Драко
Любовные романы:
любовно-фантастические романы
7.30
рейтинг книги
Драконий подарок

Очешуеть! Я - жена дракона?!

Амеличева Елена
Фантастика:
юмористическая фантастика
5.43
рейтинг книги
Очешуеть! Я - жена дракона?!

Идеальный мир для Лекаря 9

Сапфир Олег
9. Лекарь
Фантастика:
боевая фантастика
юмористическое фэнтези
6.00
рейтинг книги
Идеальный мир для Лекаря 9