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

на главную

Жанры

Эффективное использование 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
повышает уровень абстракции и упрощает программирование, документирование, усовершенствование и сопровождение программы.

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

Измена. Я отомщу тебе, предатель

Вин Аманда
1. Измены
Любовные романы:
современные любовные романы
5.75
рейтинг книги
Измена. Я отомщу тебе, предатель

Сводный гад

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

Мимик нового Мира 6

Северный Лис
5. Мимик!
Фантастика:
юмористическая фантастика
попаданцы
рпг
5.00
рейтинг книги
Мимик нового Мира 6

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

Сапфир Олег
2. Лекарь
Фантастика:
юмористическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 2

Начальник милиции

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

Магия чистых душ

Шах Ольга
Любовные романы:
любовно-фантастические романы
5.40
рейтинг книги
Магия чистых душ

Темный Патриарх Светлого Рода 4

Лисицин Евгений
4. Темный Патриарх Светлого Рода
Фантастика:
фэнтези
юмористическое фэнтези
аниме
5.00
рейтинг книги
Темный Патриарх Светлого Рода 4

Стрелок

Астахов Евгений Евгеньевич
5. Сопряжение
Фантастика:
боевая фантастика
постапокалипсис
рпг
5.00
рейтинг книги
Стрелок

На границе империй. Том 6

INDIGO
6. Фортуна дама переменчивая
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
5.31
рейтинг книги
На границе империй. Том 6

Архил…? Книга 3

Кожевников Павел
3. Архил...?
Фантастика:
фэнтези
попаданцы
альтернативная история
7.00
рейтинг книги
Архил…? Книга 3

Доктора вызывали? или Трудовые будни попаданки

Марей Соня
Фантастика:
юмористическая фантастика
попаданцы
5.00
рейтинг книги
Доктора вызывали? или Трудовые будни попаданки

Лорд Системы 11

Токсик Саша
11. Лорд Системы
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Лорд Системы 11

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

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

Последний попаданец 2

Зубов Константин
2. Последний попаданец
Фантастика:
юмористическая фантастика
попаданцы
рпг
7.50
рейтинг книги
Последний попаданец 2