130
процессе сохранения коллекции на носителе информации или в любой момент при отсутствии
активных итераторов и курсоров.
Иногда объект может находиться сразу как во вставленном, так и в удаленном состоянии; вставка
произошла после того, как итератор был сконструирован, а удаление — до уничтожения итератора. В
сущности, для каждого объекта можно вести целый журнал вставок и удалений, если для этих событий
хватит жизненного срока вашего итератора. Для ведения такого журнала подходят многие различные
структуры данных. Эта побочная тема достаточно интересна, хотя она и не имеет особого отношения к
рассматриваемым идиомам С++. Чтобы обеспечить необходимый уровень инкапсуляции, мы внесем
некоторые изменения в концепцию внутреннего итератора из предыдущего раздела.
Класс временных меток
Следующий класс инкапсулирует временные пометки.
Его можно модифицировать, чтобы вместо
последовательного счетчика использовались показания системных часов — для клиента это глубоко
безразлично. Обратите внимание: конструктор копий и оператор
=
не перегружаются. При передаче
Timestamp
по значению создается временный объект
Timestamp
с тем же временем, что и в исходном
объекте, а в случае присваивания одного
Timestamp
другому левосторонний объект приобретает ту же
метку, что и правосторонний.
class Timestamp {
private:
static
int
last_time;
//
Используется для присваивания числа
int
stamp;
public:
Timestamp() : stamp(++last_time) {}
bool operator>(Timestamp ts) { return stamp > ts.stamp; }
bool operator>=(Timestamp ts) { return stamp >= ts.stamp; }
bool operator<(Timestamp ts) { return stamp < ts.stamp; }
bool operator<=(Timestamp ts) { return stamp <= ts.stamp; }
bool operator==(Timestamp ts) { return stamp == ts.stamp; }
bool operator!=(Timestamp ts) { return stamp != ts.stamp; }
};
Внутренний итератор с временной пометкой
Внутренний итератор также необходимо модифицировать, чтобы он учитывал присутствие временных
пометок. Соответствующие фрагменты интерфейса приведены ниже. Подробности реализации в
значительной мере определяются структурами данных коллекции:
class InternalIterator {
public:
bool
More(Timestamp
as_of);
Foo*
Next(Timestamp
as_of);
bool
Peek(Timestamp
as_of);
};
Внутренний итератор будет пропускать объекты, отсутствовавшие в коллекции в указанное время.
Способы внутренней реализации
Один из возможных путей реализации такого поведения — связать с
каждой позицией коллекции
вектор временных пометок, в котором самый старый элемент будет соответствовать исходной вставке,
а последующие элементы — поочередно описывать последующие вставки и удаления. Если вектор
содержит нечетное количество элементов, объект в настоящее время находится в коллекции, а первый
элемент вектора относится к моменту последней вставки. Если число элементов четное, объект
отсутствует в коллекции, а первый элемент описывает момент последнего удаления. В процессе
уплотнения коллекции уплотняются и журналы удалений — в них остается
лишь момент последней