Standart template library (STL). Продолжение.

1. Инвалидация итераторов.

Инвалидацией итератора (от англ. invalid) называется процесс, при котором итератор перестает указывать туда, куда он должен указывать, т.е. итератор становится невалидным.
В разных контейнерах инвалидация происходит в разные моменты:
• List : при удалении и при добавлении элемента происходит инвалидация только этого итератора
• Vector : при удалении — инвалидация этого итератора и всех после него; при добавлении — инвалидация всех итераторов
• Deque : при удалении или добавлении первого и последнего элементов — инвалидация начало и конца; при добавлении или удалении остальных элементов — инвалидация всех итераторов.

List Vector Deque
Удаление Конкретный итератор Конкретный итератор и все после него При удалении первого и последнего элементов — начало и конца;
При удалении остальных элементов — всех итераторов
Добавление Конкретный итератор Все итераторы см. удаление

2. Ассоциативные контейнеры

a. SET<> упорядоченное множество

Добавление элементов в контейнер осуществляется с помощью операции insert:

 set < int > s;
 s.insert(20);

Операция insert возвращает pair, первым элементом которой является итератор на только что добавленный элемент, либо на элемент с таким же значением (если он уже был добавлен в set). Вторым элементом этой пары является параметр bool, который имеет значение true в случае, если новый элемент был добавлен, и false — если элемент с таким значением уже существовал.
Внутри set организован как сбалансированное дерево (АВЛ-дерево или красно-черное дерево). Соответственно операции insert (вставка) и find (поиск) выполняются за O(logn).
Операцию find можно использовать для проверки наличия элемента в контейнере следующим образом:

if (s.find(10) == s.end()) {...} //т.е. в случае, если элемент не найден find возвращает итератор на конец контейнера

Итератор set-а не позволяет изменять значение, на которое он указывает. Чтобы поменять какой-то элемент, необходимо сперва удалить его с помощью erase, а потом добавить нужный элемент с помощью insert.
В качестве параметра в set может быть использован только тип, для которого определена операция "<"

 set < int > s; //Для int определен оператор "<"

Определить оператор "<" можно самостоятельно(см. ниже).

b. multiset<> мультимножество

Предназначено для хранения объектов,которые могут повторяться.
Multiset очень похоже на set, за исключением операции find: она возвращает итератор, если соответствующий элемент найден, и multiset::end — если элемента нет в контейнере.
В связи с тем, что в multiset несколько элементов могут совпадать, для этого контейнера определены несколько дополнительных функций:
• lower_bound возвращает итератор на первый найденный элемент
• upper_bound возвращает итератор на следующий за последним
• equal_range возвращает пару итераторов, задающую промежуток между первым и последним найденным элементами
Чтобы посчитать количество элементов с определенным ключом, достаточно в цикле пробежать от lower_bound до upper_bound и посчитать количество итераций.
Если ни одного элемента не найдено — lower_bound = upper_bound
Пример использования:

  multiset < int > myMultiset;
  multiset < int >::iterator it, itLow, itUp;

  for (int i = 1; i < 8; i++) {
	mymultiset.insert(i * 10); // 10 20 30 40 50 60 70
  }
  itLow = myMultiset.lower_bound (30);  
  itUp= myMultiset.upper_bound (40);            

  mymultiset.erase(itLow,itUp);   // стираем все в промежутке от 30 до 40

c. map< , >

Организовано как дерево, которое хранит пары значений.
Добавление осуществляется следующим образом:

std::map < std::string, size_t > m;
m.insert(std::pair("Vasia", 100)); // добавление пары значений
или

m.insert(std::make_pair("Vasia", 100)); // make_pair сам угадывает типы по введенным данным
Изменение элемента осуществляется за O(logn):

m["Vasia"] = 1000;
Поиск элемента возвращает итератор на пару значений:

it = m.find("Vasia");
it -> first; // первое значение элемента
it -> second;  //второе значение
В map значение ключа изменить нельзя, так как по первому элементу строится дерево, и поменять ее можно, только удалив элемент и добавив нужный (с помощью erase-insert). Вторую же часть можно менять, потому что она не влияет на порядок сортировки.

d. multimap< , >

Multimap очень похожа на multiset.

3.Предикаты и функторы

Пусть у нас есть структура:

struct Person {
   std::string Name;
   std::string University;
   int Age;
}
Допустим, мы хотим сортировать Person не только по имени (Name), но и по возрасту (Age) и университету (University).
Для этого нам нужно переопределить оператор "<". Мы можем это сделать внутри структуры Person, но тогда мы не сможем упорядочивать данное множество несколькими способами. Если же нам нужна эта возможность, нам необходимо волпользоваться функторами:

bool operator < (Person const& a, Person const& b) {
  ... //наш вариант сортировки
  return a.name $lt; b.name; // например
}
Но в set нужно передавать класс или структуру.
Создадим структуру:

struct by_name {
  bool operator < () {
    ...
  }
}
Такая функция внутри структуры (класса) будет называться функтором или предикатом. Предикат — это функтор, который возвращает bool.
Теперь в set мы можем передать в качестве другого параметра структуру by_name, с помощью которой будет сортироваться Person:

set < Person, by_name > s;
NB! Оператор "<" должен быть строгим.

4. Итераторы

Категории итераторов:

1. Random-access iterator
Имеют ту же функциональность, что и обычные указатели. Это наиболее полные в плане функциональности итераторы. Есть арифметика итераторов.

2. Bidirectional iterator
Специально разработанные итераторы, предназначенные для последовательного доступа в обоих направлениях: вперед и назад. Только операторы ++ и --.

3. Forward iterator
Предназначены для последовательного доступа от начала к концу. Только оператор ++.

4.1 Output iterator
Предназначены для последовательных операций вывода. Значение, на которое указывает итератор, записывается, и после этого итератор увеличивается.

4.2 Input iterator
Предназначены для последовательных операций ввода. Значение, на которое указывает итератор, считывается, и после этого итератор увеличивается.

Что еще полезно знать об итераторах:

• iter_swap()
Меняет значение переменных по двум итераторам. Аналогична функции std::swap() для двух значений. Функция находится в
• std::distance(p, q)
Возвращает расстояние между двумя итераторами.
Для итераторов типа Random-access функция использует operator-. Для остальных категорий итераторов используются operator++ и operator--
• iterator_traits
Это template class позволяющий получить информацию об итераторе: категорию, тип итерируемых значений и т.д. Каждая категория итераторов соотносится с iterator_traits, который имеет следующие поля:
::value_type  — тип элемента, на который может указывать итератор данного типа
::pointer, reference  — тип указателя/ссылки
::category  — собственно категория итератора