Бьерн Страуструп.
Язык программирования С++
215
что можно при выполнении итератора обработать случаи, когда элементы добавляются или удаляются
из контейнера. Этот и некоторые другие способы задания итераторов были бы невозможны, если бы
итератор зависел от функции пользователя, в которой есть указатели на элементы из контейнера. Как
правило, контейнер или его итераторы реализуют понятие "установить итерацию на начало" и понятие
"текущего элемента".
Если понятие текущего элемента предоставляет не итератор, а сам контейнер, итерация происходит в
принудительном порядке по отношению к контейнеру аналогично тому, как поля связи принудительно
хранятся в объектах из контейнера. Значит трудно одновременно вести две итерации для одного
контейнера, но расходы на память и время при такой организации итерации близки к оптимальным.
Приведем пример:
class slist_base {
//
...
slink* last; // last->next
голова списка
slink* current; //
текущий элемент
public:
//
...
slink* head() { return last?last->next:0; }
slink* current() { return current; }
void set_current(slink* p) { current = p; }
slink* first() { set_current(head()); return current; }
slink*
next();
slink*
prev();
};
Подобно тому, как в целях эффективности и компактности программы можно использовать для одного
объекта как список с принудительной связью, так и список без нее, для одного контейнера можно
использовать принудительную и непринудительную итерацию:
void f(Islist
& ilst)
// медленный поиск имен-дубликатов
{
list_iter slow(ilst); //
используется итератор
name*
p;
while (p = slow()) {
ilst.set_current(p); // рассчитываем на текущий элемент
name*
q;
while (q = ilst.next())
if
(strcmp(p->string,q->string)
==
0)
cout
<<
"
дубликат" << p << '\n';
}
}
Еще один вид итераторов показан в $$8.8.
Достарыңызбен бөлісу: