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