Это работает для указателей на любые объекты, для которых определен operator<
. Объявление набора с его использованием имеет такой вид.
set<string*, ptrLess<string> > setStrPtr;
set
поддерживает многие из функций, поддерживаемых другими стандартными последовательными контейнерами (например, begin
, end
, size
, max_size
) и другими ассоциативными контейнерами (например, insert
, erase
, clear
, find
).
При использовании set
помните, что при каждом изменении состояния набора выполняется его сортировка. Когда число его элементов велико, логарифмическая сложность добавления или удаления элементов может оказаться очень большой — вам действительно требуется, чтобы объекты сортировались каждый раз? Если нет, то для повышения производительности используйте vector
или list
и сортируйте его только тогда, когда это необходимо, что обычно имеет сложность порядка n*log(n).
6.9. Хранение контейнеров в контейнерах
Имеется несколько экземпляров стандартного контейнера (list
, set
и т.п.) и требуется сохранить их в еще одном контейнере.
Сохраните в главном контейнере указатели на остальные контейнеры. Например, можно использовать map
для хранения ключа типа string
и указателя на set
как значения. Пример 6.12 показывает простой класс журналирования транзакций, который хранит данные как map из пар, состоящих из string
и указателей на set
.
#include <iostream>
#include <set>
#include <map>
#include <string>
using namespace std;
typedef set<string> SetStr
typedef map<string, SetStr*> MapStrSetStr;
// Фиктивный класс базы данных
class DBConn {
public:
void beginTxn() {}
void endTxn() {}
void execSql(string& sql) {}
};
class SimpleTxnLog {
public:
SimpleTxrLog() {}
~SimpleTxrLog() {purge();}
// Добавляем в список выражение SQL
void addTxn(const string& id
const string& sql) {
SetStr* pSet = log_[id]; // Здесь создается запись для
if (pSet == NULL) { // данного id, если ее еще нет
pSet = new SetStr();
log_[id] = pSet;
}
pSet->insert(sol);
}
// Применение выражений SQL к базе данных, по одной транзакции
// за один раз
void apply() {
for (MapStrSetStr::iterator p = log_.begin();
p != log_.end(); ++p) {
conn_->beginTxn();
// Помните, что итератор отображения ссылается на объект
// типа pair<Key,Val>. Указатель на набор хранится в p->second.
for (SetStr::iterator pSql = p->second->begin();
pSql != p->second->end(); ++pSql) {
string s = *pSql;
conn_->execSql(s);
cout << 'Executing SQL: ' << s << endl;
}
conn_->endTxn();
delete p->second;
}
log_.clear();
}
void purge() {
for (MapStrSetStr::iterator p = log_.begin();
p != log_.end(); ++p)
delete p->second;
log_.clear();
}
//...
private:
MapStrSetStr log_;
DBConn* conn_;
}
;
Пример 6.12 предлагает ситуацию, где может потребоваться хранение одного контейнера в другом. Представьте, что требуется сохранить набор выражений SQL в виде пакета, выполнить их в будущем все сразу для реляционной базы данных. Именно это делает SimpleTxnLog
. Чтобы сделать его еще полезнее, можно добавить в него другие методы, а для обеспечения безопасности — добавить