Повторная проверка итератора STL для конечного (прошедшего) итератора?

См. Связанные вопросы по аннулированию итератора за прошлым:
этот, этот.

Это больше вопрос дизайна, а именно есть ли (в STL или в другом месте) такое понятие, как последний итератор «повторной проверки»?

Что я подразумеваю под этим, и случай использования: предположим, что алгоритм должен «хвостить» контейнер (такой как очередь). Пересекает контейнер до end() достигается, затем паузы; независимо от этого другая часть программы ставит в очередь больше элементов в очереди. Как это возможно для алгоритма (РЕДАКТИРОВАТЬ) продуктивно скажем, «было ли в очереди больше элементов» при удержании ранее завершенного итератора (назовите его tailIt)? (это будет означать, что он может проверить, tailIt == container.end() еще, и если это неверно, сделайте вывод tailIt теперь действует и указывает на первый элемент, который был вставлен).

Пожалуйста, не отклоняйте вопрос как «нет, нет» — я стремлюсь сформировать суждение о том, как разработать некоторую логику идиоматическим образом и иметь много вариантов (на самом деле рассматриваемые итераторы под рукой. структура данных, для которой я Можно предоставить эту собственность — end () повторная проверка — но я бы хотел судить, если это хорошая идея).


РЕДАКТИРОВАТЬ: дал понять, что у нас есть итератор tailIt а также ссылка на container, Тривиальный обход того, что я пытаюсь сделать, это также помните count : = сколько предметов вы обработали, а затем проверьте container.size() == count все же, а если нет, стремиться container[count] и продолжить обработку оттуда. Это имеет много недостатков (дополнительное состояние, допущение, что контейнер не появляется спереди (!), Произвольный доступ для эффективного поиска).

4

Решение

Не в общем. Вот некоторые проблемы с вашей идеей:

  • Некоторые устаревшие итераторы вообще не «указывают» на блок данных; на самом деле это будет верно для любой итератор, кроме векторного итератора. Таким образом, в целом, существующий конечный итератор просто никогда не станет действительным итератором для данных;
  • Итераторы часто становятся недействительными при изменении контейнера — хотя это не всегда так, это также исключает общее решение, которое основано на разыменовании некоторого итератора до мутации;
  • Действительность итератора ненаблюдаема — перед разыменованием итератора вам уже нужно знать, является ли он действительным. Это информация, которая поступает откуда-то, обычно из вашего мозга … под этим я подразумеваю, что разработчик должен прочитать код и сделать определение на основе его структуры и потока.

Сложите все это вместе, и станет ясно, что конечный итератор просто не может быть использован таким образом, поскольку интерфейс итератора в настоящее время разрабатывается. Итераторы ссылаются на данные в диапазоне, а не на контейнер; тогда понятно, что они не содержат никакой информации о контейнере, и если контейнер вызывает изменение диапазона, нет иного объекта, о котором итератор знает, что он может попросить выяснить это.

Можно ли создать описанную логику? Конечно! Но с другим интерфейсом итератора (и поддержкой из контейнера). Вы можете обернуть контейнер в свой собственный тип класса, чтобы сделать это. Однако я не советую делать вещи, которые выглядят как стандартные итераторы, но ведут себя иначе; это будет очень запутанно.

Вместо этого инкапсулируйте контейнер и предоставьте свою собственную функцию-обертку, которая может напрямую выполнять любое действие после добавления в очередь, которое вам нужно. Вам не нужно следить за состоянием конечного итератора, чтобы достичь своей цели.

5

Другие решения

В случае с 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++); петля.
Но, учитывая сказанное, я не могу заверить вас, насколько хорошо компилятор будет оптимизировать, как развертывание циклов, с помощью этих итераторов. Я предполагаю, что это все еще сделает довольно хорошую работу.

1

По вопросам рекламы [email protected]