Существует ли метод c.ended (iter), совместимый с циклами for на основе диапазона?

0

Если я правильно понимаю, for-loops на основе диапазона проверят конечное условие, вызывая iter! = C.end() на вашем итераторе (iter) и коллекции (c). Но предположим, что у меня есть коллекция, где генерация итератора для c.end() не особенно проста или эффективна?

Может ли метод for-loops на основе диапазона распознавать другой метод (что-то вроде bool c.ended(iter) const), который примет итера как аргумент и проверяет, достиг ли он конца? Есть ли какой-то трюк с шаблонами, чтобы получить тот же эффект?

ПРИМЕР:

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

ПРИМЕР 2:

Хорошо, ясно, что пример 1 был плохим. Я буду ближе к тому, что я на самом деле делаю (хотя там еще немного). forward_list может расстраивать, потому что у него нет метода erase(). Там только erase_after(). Поэтому, чтобы исправить это, я хочу иметь альтернативный forward_list, где итератор внутренне содержит указатель на узел до того, на который он ссылается. Теперь у меня может быть метод erase(), который ведет себя правильно (за счет того, что вам нужно беспокоиться о том, может ли что-то еще стереть узел, на котором я внутренне сижу). Теперь создание итератора до конца() включает в себя выяснение того, что является самым последним элементом в списке. Я мог бы поддерживать указатель, но это действительно просто потраченная впустую потерянная память, потому что проверка того, должен ли iterator == end() быть легким. Я могу просто проверить, если p_my_node → next == NULL.

  • 0
    Как можно использовать что-то кроме end() для проверки конца контейнера? Если это дешевле, чем end() , почему end() не реализована с точки зрения этого? Или, может быть, вы заблуждаетесь, что диапазон, основанный на цикле, будет вызывать end() для каждой итерации?
  • 0
    Вызов end() будет «кэширован», что эквивалентно auto __begin = c.begin(), __end = c.end() (если ваш контейнер предоставляет функции-члены begin() и end() ). Тип будет выведен из c.begin() , а не из c.end() .
Показать ещё 5 комментариев
Теги:
for-loop
iterator
range

2 ответа

2
Лучший ответ

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

Если у вас есть что-то другое, кроме c.end() которое может использоваться как проверка на конец диапазона и дешевле вычислять, чем c.end(), почему c.end() не просто?


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

class Iterator {
   node *ptr;    // nullptr == end() by convention
public:
   Iterator() : ptr() {}
   Iterator(node *ptr) : ptr(ptr) {}
   bool isEnd() const {
      return !ptr || ptr->isEnd();
   }
   friend bool operator==(Iterator const& lhs, Iterator const& rhs) {
      return (lhs.isEnd() && rhs.isEnd())
          || (lhs.ptr == rhs.ptr);
   } 
};

Теперь реализация end() - это дешевая реализация:

Iterator Container::end() {
   return Iterator();
}
  • 0
    Потому что мне нужен доступ к самому итератору, чтобы узнать, в конце ли он. Я не могу просто сгенерировать, как выглядит итератор end ()
  • 0
    В качестве примера представьте forward_list, который внутренне не содержит указатель на узел заголовка (/ end), но может распознать этот узел, когда он его видит
Показать ещё 6 комментариев
2

Возможным решением может быть создание специального типа итератора для c.end() а затем сделать your_iterator::operator==() c.ended(iter) и вернуть это значение, когда он увидит конечный итератор в качестве аргумента. Я думаю, вы можете создать специальный перегруженный operator== для разных типов итераторов (end iterator), но если это хорошее решение трудно сказать заранее. Но вы можете иметь специальный флаг или специальное значение в конце итератора и иметь это поведение во время выполнения в operator==().

  • 1
    Использование другого типа для итератора «за конец» ( end() ) и других итераторов приводит к проблемам со стандартной библиотекой. Часто предполагается, например, в алгоритмах и в цикле, основанном на диапазоне, что они имеют один и тот же тип.
  • 1
    @DyP приятно знать, спасибо, но проверка времени выполнения должна работать, я считаю.
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню