Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
template_metaprogramming_ru.docx
Скачиваний:
12
Добавлен:
01.07.2025
Размер:
774 Кб
Скачать
☆

Stl алгоритмы

Алгоритмы STL представляют собой мощные абстракции, работа которых поддерживается другими абстракциями и сокрыта от пользователя, это делает использование алгоритма очень гибким, но со своими нюансами:

Рассмторим 2 альтернативные версии прибавления числа 42 к каждому элементу последовательности:

// "abstraction"

std::transform(

v.begin(), v.end(), v.begin(),

std::bind2nd(std::plus<int>(),42)

);

// handwritten loop

typedef std::vector<int>::iterator v_iter;

for(v_iter i = v.begin(), last = v.end(); i != last; ++i)

*i += 42;

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

Эти недостатки, однако, могут быть преодолены довольно легко. Например, мы можем использовать библиотеку Boost Lambda, которая стала прообразом лямбд в MPL, лямбды помогут упростить и прояснить работу с функторами времени выполнения.

В следующих примерах заполнительно «_1» ссылается на прототип объекта из библиотеки Boost Lambda (в пространстве имен boost::lambda). Заполнители времени выполнения из Boost Lambda явялются прообразами заполнителей MPL.

std::transform(v.begin(), v.end(), v.begin(), _1 + 42);

или так:

std::for_each(v.begin(), v.end(), _1 += 42);

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

По примеру видно, что проблема не в алгоритме, а в том как его используют. Основной проблемой была STL среда для генерирования аргумента для функции алгоритма.

Детали правильного использования stl:

  • Создание временных итераторов.

  • Правильные объявления типа итераторов, даже в обобщенном коде.

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

  • Использование известных оптимизаций (например, раскрутка цикла).

  • Обобщенные условие завершения циклов: например, алгоритм for_each использует pos != finish, а не pos < finish, т.к. в противном случае, в данном алгоритме нельзя было бы использовать итератор произвольного доступа.

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

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]