Назначение
В QList есть и итераторы в стиле Java, и итераторы в стиле STL:
| Характеристика | Java-стиль | STL-стиль |
|---|---|---|
| Уровень | Высокоуровневые | Низкоуровневые |
| Простота | Проще в использовании | Требуют больше внимания |
| Эффективность | Немного менее эффективны | Более эффективны |
| Позиция | Указывают между элементами | Указывают непосредственно на элемент |
Альтернативой использованию итераторов является работа с индексами. Большинство функций-членов QList принимают индекс в качестве первого параметра, что позволяет получать доступ, вставлять и удалять элементы без использования итераторов.
Класс QMutableListIterator<T> позволяет перебирать QList<T> и изменять список прямо во время обхода. Если модификация не нужна, следует использовать чуть более быстрый QListIterator<T>.
Конструктор QMutableListIterator принимает QList в качестве аргумента. После построения итератор находится в самом начале списка.
Как работает итератор
Функция next() возвращает следующий элемент в списке и продвигает итератор. В отличие от STL-итераторов, Java-итераторы указывают между элементами, а не непосредственно на элементы:
- Первый вызов
next()переводит итератор в положение между первым и вторым элементом и возвращает первый элемент. - Второй вызов
next()продвигает итератор между вторым и третьим элементом, возвращая второй элемент. - И так далее.
Пример удаления элементов
Фрагмент кода, который удаляет все значения больше 20:
QList<int> list;
list << 2 << 11 << 54 << 3 << 6 << 2 << 76 << 11 << 3 << 2;
QMutableListIterator<int> i(list);
while (i.hasNext()) {
int currentValue = i.next();
if (currentValue > 10)
i.remove();
}
qDebug() << list;
До:
QList(2, 11, 54, 3, 6, 2, 76, 11, 3, 2)
После:
QList(2, 3, 6, 2, 3, 2)
Перебор в обратном порядке
Для обхода списка от конца к началу используется toBack() и previous():
QMutableListIterator<int> i(list);
i.toBack();
while (i.hasPrevious())
qDebug() << i.previous();
Метод toBack() перемещает итератор за последний элемент, а previous() возвращает элементы в обратном порядке, продвигая итератор к началу.
Ключевые методы QMutableListIterator
| Метод | Назначение |
|---|---|
hasNext() | Есть ли следующий элемент |
next() | Вернуть следующий элемент и продвинуть итератор |
hasPrevious() | Есть ли предыдущий элемент |
previous() | Вернуть предыдущий элемент и откатить итератор |
remove() | Удалить текущий элемент |
setValue() | Заменить текущий элемент |
insert() | Вставить элемент в текущую позицию |
toFront() | Переместить итератор в начало |
toBack() | Переместить итератор в конец |
findNext() / findPrevious() | Найти элемент начиная с текущей позиции |
Важные замечания
remove()удаляет элемент, возвращённый последнимnext()илиprevious(). Его нельзя вызывать до первого вызоваnext()— иначе поведение неопределённо.- Не используйте STL-итераторы при удалении. После
erase()они инвалидируются, что требует ручной корректировки. Java-итераторы решают эту проблему автоматически. QMutableListIteratorизменяет оригинальный список — копии не создаются, все изменения применяются напрямую.- Для
QVector,QLinkedListи других контейнеров существуют аналогичные классы:QMutableVectorIterator,QMutableLinkedListIteratorи т. д. - Для простых случаев без модификации используйте индексы или range-based
for— это самый быстрый и читаемый вариант:cppfor (int value : list) { qDebug() << value; } - Удаление в цикле по индексу требует осторожности — после удаления индексы сдвигаются:cppfor (int i = 0; i < list.size(); ) { if (list[i] > 10) list.removeAt(i); else ++i; }Java-итераторы избавляют от этой ручной работы.
- В
QListстоимость удаления из середины выше, чем вQLinkedList— если предполагается много удалений, стоит рассмотреть другой контейнер.
Итог
QMutableListIterator<T> — удобный инструмент для перебора и модификации QList, особенно при удалении элементов в цикле. Java-итераторы работают на более высоком уровне абстракции, чем STL, и избавляют от ошибок, связанных с инвалидацией указателей и сдвигом индексов. Их главный недостаток — чуть меньшая производительность, которая в большинстве задач несущественна. Если модификация не требуется, стоит выбрать QListIterator<T> или обычный обход по индексам.