Шаг 108.
Библиотека STL.
Модифицирующие алгоритмы и ассоциативные контейнеры

    На этом шаге мы рассмотрим вопросы удаления элементов из ассоциативных контейнеров.

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

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

    Возникает вопрос: как же удалить элементы из ассоциативного контейнера? Ответ прост: воспользуйтесь собственными функциями контейнера! В каждом ассоциативном контейнере предусмотрены функции удаления элементов. Например, элементы можно удалить функцией erase():

//---------------------------------------------------------------------------

#include <vcl.h>
#include <iostream>
#include <iterator>
#include <set>
#include <string>
#include <algorithm>
#include <conio.h> //необходимо для getch()
#pragma hdrstop

//---------------------------------------------------------------------------

#pragma argsused
using namespace std;
std::string ToRus(const std::string &in)
{
  char *buff = new char [in.length()+1];
  CharToOem(in.c_str(),buff);
  std::string out(buff);
  delete [] buff;
  return out;
}

int main(int argc, char* argv[])
{
  set<int> coll;

  // Вставка элементов со значениями от 1 до 9
  for (int i=1; i<=9; ++i) {
    coll.insert(i);
  }
  // Вывод всех элементов коллекции
  cout << ToRus("Множество чисел:\n");
  copy (coll.begin(), coll.end(), // Источник
    ostream_iterator<int>(cout," ")); // Приемник
  cout << endl;

  // Удаление всех элементов со значением 3
  // - алгоритм remove() не работает
  // - используем функцию erase()

  int num = coll.erase(3);
  // Вывод количества "удаленных" элементов
  cout << ToRus("Количество удаленных элементов: ") << num << endl;

  // Вывод всех элементов модифицированной коллекции
  cout << ToRus("Измененное множество чисел:\n");
  copy (coll.begin(), coll.end(), // Источник
    ostream_iterator<int>(cout," ")); // Приемник

  cout << endl;

  getch();
  return 0;
}
//---------------------------------------------------------------------------
Текст этого примера можно взять здесь.

    Контейнеры поддерживают несколько версий функции erase(). Только та версия, единственным аргументом которой является значение удаляемого элемента (или элементов), возвращает количество удаленных элементов. Разумеется, если дубликаты в коллекции запрещены (как в множествах и отображениях), возвращаемое значение функции может быть равно только 0 или 1.

    Результат работы программы выглядит так:


Рис.1. Результат работы приложения

    На следующем шаге мы рассмотрим алгоритмы и функции классов.




Предыдущий шаг Содержание Следующий шаг