См. Связанные вопросы по аннулированию итератора за прошлым:
этот, этот.
Это больше вопрос дизайна, а именно есть ли (в STL или в другом месте) такое понятие, как последний итератор «повторной проверки»?
Что я подразумеваю под этим, и случай использования: предположим, что алгоритм должен «хвостить» контейнер (такой как очередь). Пересекает контейнер до end()
достигается, затем паузы; независимо от этого другая часть программы ставит в очередь больше элементов в очереди. Как это возможно для алгоритма (РЕДАКТИРОВАТЬ) продуктивно скажем, «было ли в очереди больше элементов» при удержании ранее завершенного итератора (назовите его tailIt
)? (это будет означать, что он может проверить, tailIt == container.end()
еще, и если это неверно, сделайте вывод tailIt
теперь действует и указывает на первый элемент, который был вставлен).
Пожалуйста, не отклоняйте вопрос как «нет, нет» — я стремлюсь сформировать суждение о том, как разработать некоторую логику идиоматическим образом и иметь много вариантов (на самом деле рассматриваемые итераторы под рукой. структура данных, для которой я Можно предоставить эту собственность — end () повторная проверка — но я бы хотел судить, если это хорошая идея).
РЕДАКТИРОВАТЬ: дал понять, что у нас есть итератор tailIt
а также ссылка на container
, Тривиальный обход того, что я пытаюсь сделать, это также помните count
: = сколько предметов вы обработали, а затем проверьте container.size() == count
все же, а если нет, стремиться container[count]
и продолжить обработку оттуда. Это имеет много недостатков (дополнительное состояние, допущение, что контейнер не появляется спереди (!), Произвольный доступ для эффективного поиска).
Не в общем. Вот некоторые проблемы с вашей идеей:
Сложите все это вместе, и станет ясно, что конечный итератор просто не может быть использован таким образом, поскольку интерфейс итератора в настоящее время разрабатывается. Итераторы ссылаются на данные в диапазоне, а не на контейнер; тогда понятно, что они не содержат никакой информации о контейнере, и если контейнер вызывает изменение диапазона, нет иного объекта, о котором итератор знает, что он может попросить выяснить это.
Можно ли создать описанную логику? Конечно! Но с другим интерфейсом итератора (и поддержкой из контейнера). Вы можете обернуть контейнер в свой собственный тип класса, чтобы сделать это. Однако я не советую делать вещи, которые выглядят как стандартные итераторы, но ведут себя иначе; это будет очень запутанно.
Вместо этого инкапсулируйте контейнер и предоставьте свою собственную функцию-обертку, которая может напрямую выполнять любое действие после добавления в очередь, которое вам нужно. Вам не нужно следить за состоянием конечного итератора, чтобы достичь своей цели.
В случае с std :: queue нет, нет (хех). Не потому, что итераторы для очереди становятся недействительными после того, как что-то выдвинуто, а потому, что в очереди вообще нет итераторов.
Что касается других типов итераторов, большинство (или любой из них) не требуют ссылки на держатель контейнера (управляющий объект, содержащий всю информацию о базовых данных). Что является компромиссом между эффективностью и гибкостью. (Я быстро проверил реализацию gcc’s std :: vector :: iterator)
Можно написать реализацию для типа итератора, который хранит ссылку на владельца в течение его времени жизни, таким образом, итераторы никогда не должны быть аннулированы! (если держатель не std :: move’d)
Теперь добавь в мой профессионал мнение, Я не возражаю против просмотра safe_iterator / flex_iterator для случаев, когда итератор обычно будет недействительным во время итераций.
Возможный пользовательский интерфейс:
for (auto v : make_flex_iterator(my_vector)) {
if (some_outside_condition()) {
// Normally the vector would be invalidated at this point
// (only if resized, but you should always assume a resize)
my_vector.push_back("hello world!");
}
}
Буквально повторная проверка итераторов может быть слишком сложной для построения в зависимости от случая использования (я не знаю, с чего начать), но разработка итератора, который просто никогда не делает недействительными, довольно тривиальна, так как требует только дополнительных затрат for (size_t i = 0; i < c.size(); i++);
петля.
Но, учитывая сказанное, я не могу заверить вас, насколько хорошо компилятор будет оптимизировать, как развертывание циклов, с помощью этих итераторов. Я предполагаю, что это все еще сделает довольно хорошую работу.