Литмир - Электронная Библиотека
A
A

Б.6. Утилиты библиотеки STL

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

Б.6.1. Вставки

Запись результатов в контейнер с помощью итератора подразумевает, что элементы, на которые указывает итератор, можно перезаписать. Это открывает возможность для переполнения и последующего повреждения памяти. Рассмотрим следующий пример:

void f(vector<int>& vi)

{

  fill_n(vi.begin(),200,7); // присваиваем 7 элементам

                              // vi[0]..[199]

}

Если вектор

vi
содержит меньше 200 элементов, то возникает опасность. В заголовке
<iterator>
стандартная библиотека предусматривает три итератора, позволяющих решить эту проблему с помощью добавления (вставки) элементов в контейнер, а не перезаписи его старых элементов. Для генерирования этих трех итераторов вставки используются три функции.

Программирование. Принципы и практика использования C++ Исправленное издание - _406.png

Для правильной работы алгоритма

inserter(c,p)
необходимо, чтобы итератор p был корректным итератором для контейнера
c
. Естественно, каждый раз при записи очередного элемента с помощью итератора вставки контейнер увеличивается на один элемент. При записи алгоритм вставки добавляет новый элемент в последовательность с помощью функции
push_back(x)
,
c.push_front()
или
insert()
, а не перезаписывает существующий элемент. Рассмотрим следующий пример:

void g(vector<int>& vi)

{

  fill_n(back_inserter(vi),200,7); // добавляет 200 семерок

                                   // в конец vi

}

Б.6.2. Объекты-функции

Многие стандартные алгоритмы принимают в качестве аргументов объекты-функции (или функции), чтобы уточнить способ решения задачи. Обычно эти функции используются в качестве критериев сравнения, предикатов (функций, возвращающих значения типа

bool
) и арифметических операций. Несколько самых общих объектов-функций описано в заголовке
<functional>
стандартной библиотеки.

Программирование. Принципы и практика использования C++ Исправленное издание - _407.png

Рассмотрим следующий пример:

vector<int> v;

// ...

sort(v.begin(),v.end(),greater<int>()); // сортировка v в убывающем

                                        // порядке

Обратите внимание на то, что предикаты

logical_and
и
logical_or
всегда вычисляют оба свои аргумента (в то время как операторы
&&
и
||
— нет).

Программирование. Принципы и практика использования C++ Исправленное издание - _408.png
Программирование. Принципы и практика использования C++ Исправленное издание - _409.png

Б.6.3. Класс pair

В заголовке

<utility>
стандартная библиотека содержит несколько вспомогательных компонентов, включая класс
pair
.

template <class T1,class T2>

  struct pair {

    typedef T1 first_type;

    typedef T2 second_type;

    T1 first;

    T2 second;

    pair();      // конструктор по умолчанию

    pair(const T1& x,const T2& y);

                 // копирующие операции:

    template<class U,class V> pair(const pair<U,V>& p
);

};

template <class T1, class T2>

  pair<T1,T2> make_pair(T1 x, T2 y) { return pair<T1,T2>(x,y); }

Функция

make_pair()
упрощает использование пар. Например, рассмотрим схему функции, возвращающей значение и индикатор ошибки.

pair<double,error_indicator> my_fct(double d)

{

  errno = 0; // очищаем индикатор ошибок в стиле языка C

             // выполняем много вычислений, связанных с переменной d,

             // и вычисляем x

  error_indicator ee = errno;

  errno = 0; // очищаем индикатор ошибок в стиле языка C

  return make_pair(x,ee);

}

Этот пример является полезной идиомой. Его можно использовать следующим образом:

pair<int,error_indicator> res = my_fct(123.456);

if (res.second==0) {

  // используем res.first

}

else {

  // Ой: ошибка

}

Б.7. Потоки ввода-вывода

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

Определения потоков ввода-вывода находятся в заголовках

<istream>
,
<ostream>
и т.п. (см. раздел Б.1.1).

Объект класса

ostream
преобразовывает объекты, имеющие тип, в поток символов (байтов).

428
{"b":"847443","o":1}