Шаг 184.
Библиотека STL. Контейнеры STL. Пример с отображениями, строками и изменением критерия сортировки на стадии выполнения

    На этом шаге мы рассмотрим более сложный пример.

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

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

#include <vcl.h>
#include <iostream>
#include <iterator>
#include <iomanip>
#include <map>
#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;
}

// Объект функции для сравнения строк
// - позволяет задать критерий сравнения во время выполнения
// - позволяет сравнивать символы без учета регистра
class RuntimeStringCmp { 
  public:
    // Константы режима сравнения
    enum cmp_mode {normal, nocase}; 
  private:
    // Используемый режим сравнения
    const cmp_mode mode;

    // Вспомогательная функция для сравнения символов без учета регистра 
    static bool nocase_compare (char c1, char c2)
    {
      return toupper(c1) < toupper(c2);
    }
  public:
    // Конструктор: инициализация критерия сравнения 
    RuntimeStringCmp (cmp_mode m=normal) : mode(m) {}
    
    // Сравнение
    bool operator() (const string& s1, const string& s2) const { 
      if (mode == normal) { 
        return s1 < s2;
      } else {
        return lexicographical_compare (s1.begin(), s1.end(),
                                        s2.begin(), s2.end(),
                                        nocase_compare);
     }
    }
};
  
// Тип контейнера:
//  - отображение
//  - ключ: string
//  - значение: string
//  - специальный тип критерия сравнения

typedef map<string,string,RuntimeStringCmp> StringStringMap;

// Функция для заполнения контейнера и вывода его содержимого 
void fillAndPrint(StringStringMap& coll);
 

int main(int argc, char* argv[])
{
  // Создание контейнера с критерием сравнения по умолчанию
  cout << ToRus("Контейнер 1 (Исходные данные):\n");
  StringStringMap coll1;
  fillAndPrint(coll1);

  // Создание объекта для сравнений без учета регистра символов
  RuntimeStringCmp ignorecase(RuntimeStringCmp::nocase);

  // Создание контейнера с критерием сравнения без учета регистра
  cout << ToRus("Контейнер 2 (Упорядоченные данные):\n");
  StringStringMap coll2(ignorecase);
  fillAndPrint(coll2);

  getch();
  return 0;
}

void fillAndPrint(StringStringMap& coll)
{
  // Вставка элементов в произвольном порядке
  coll["Deutschland"] = "Германия"; 
  coll["deutsch"] = "немецкий"; 
  coll["Haken"] = "крючок"; 
  coll["arbeiten"] = "работать"; 
  coll["Hund"] = "собака"; 
  coll["gehen"] = "идти"; 
  coll["Unternehmen"] = "компания"; 
  coll["unternehmen"] = "принять"; 
  coll["gehen"] = "ходить"; 
  coll["Bestatter"] = "услуги";

  // Вывод элементов 
  StringStringMap::iterator pos; 
  cout.setf(ios::left,ios::adjustfield); 
  for (pos=coll.begin(); pos!=coll.end(); ++pos) { 
    cout << setw(15) << pos->first.c_str() << " " 
         << ToRus(pos->second) << endl;
  }
  cout << endl;
}

//---------------------------------------------------------------------------
Текст этого примера можно взять здесь.

    Функция main() создает два контейнера и вызывает для них функцию fillAndPrint(), которая заполняет контейнеры одинаковыми элементами и выводит их содержимое. Однако контейнеры используют разные критерии сортировки.

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


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

    В первой части итоговых данных выводится содержимое первого контейнера, сравнивающего элементы оператором <. Сначала перечисляются все ключи, начинающиеся с символов верхнего регистра, а за ними следуют ключи, начинающиеся с символов нижнего регистра.

    Во второй части ключи сравниваются без учета регистра, поэтому порядок перечисления элементов изменяется. Обратите внимание - вторая часть содержит на одну строку меньше первой. Дело в том, что при сравнении без учета регистра слова "Unternehmen" и "unternehmen" оказываются равными, а критерий сортировки нашего отображения не допускает наличия дубликатов. К сожалению, в результате возникает путаница - ключу, которому должно соответствовать значение "компания", соответствует значение "принять". Вероятно, в этом примере было бы правильнее использовать мультиотображение. Обычно в качестве словарей применяется именно этот тип контейнера.

    Со следующего шага мы начнем рассматривать другие контейнеры STL.




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