end() для самодельного итератора
От: kavaj  
Дата: 20.08.07 15:44
Оценка:
Если необходимо написать самодельный итератор для определенного типа
(например для класса строчки чтобы ходить по точкам или запятым), то как
порекомендуете сделать итератор, указывающий за пределы контейнера (тот самый
мифический end()) ?

На данный момент у меня такая семантика:

std::string str;

myiter begin(str)
myiter end();


когда операциями инкремента begin проходит всю строку и выходит за границы,
то
operator!=()
будет считать его равным end'у.

Есть более элегантные решения ?
Re: end() для самодельного итератора
От: Roman Odaisky Украина  
Дата: 20.08.07 17:37
Оценка:
Здравствуйте, kavaj, Вы писали:

K>Если необходимо написать самодельный итератор для определенного типа

K>(например для класса строчки чтобы ходить по точкам или запятым), то как
K>порекомендуете сделать итератор, указывающий за пределы контейнера (тот самый
K>мифический end()) ?

Посмотри, как сделаны Boost.Iterators. А еще поищи там же Boost.Tokenizer, Boost.Regex (boost::regex_token_iterator).
До последнего не верил в пирамиду Лебедева.
Re: end() для самодельного итератора
От: Кодт Россия  
Дата: 20.08.07 19:47
Оценка: 7 (1)
Здравствуйте, kavaj, Вы писали:

K>Если необходимо написать самодельный итератор для определенного типа

K>(например для класса строчки чтобы ходить по точкам или запятым), то как
K>порекомендуете сделать итератор, указывающий за пределы контейнера (тот самый
K>мифический end()) ?

А какие требования у итератора?

Если это не более чем forward iterator, то можно сделать так:
— внутри есть признак обнулённости (которым может выступать и нулевой указатель на данные, и отрицательный дескриптор файла и т.п. — а может быть и отдельный член)
— дефолтный конструктор выставляет этот признак
— при достижении конца данных (nul, eof и т.п.) этот признак немедленно выставляется (в том числе, в конструкторе итератора на реальном наборе)
— оператор сравнения первым делом проверяет обнулённости, и если оба не обнулены, то уже сравнивает указатели и прочее.

Уже для bidirectional iterator так делать нельзя. Там end() для каждого домена должен быть свой.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[2]: end() для самодельного итератора
От: kavaj  
Дата: 20.08.07 20:41
Оценка:
Да, это input forward iterator для строчки.

Внутри есть указатель на данные и булевый флажок ready.
Если создавать дефолтным конструктором, то указатель будет нулевым и флажок будет сброшен.
Такую комбинацию я считаю за end() и оператор сравнения сначала смотрит не нулевой ли
указатель на данные у одной из сторон. Если так, то он считает, что это сравнение с end() и
дальше сравнивает только флажок.

Иначе сравнивает указатели на данные, позицию и флажок.

Собственно мне не нравится то, что пользователь должен знать как именно получить end().
Ведь его нельзя попросить у контейнера, как принято для stl контейнеров. Мне приходится
это писать писать большими буквами в хедере в первых 25 строчках. А пользователю
недоступно "естественное" использование итератора, без курения хедера.

Вот думаю может функцию-хелпер сделать типа myiter_end()...
Re[3]: end() для самодельного итератора
От: Кодт Россия  
Дата: 21.08.07 09:14
Оценка:
Здравствуйте, kavaj, Вы писали:

K>Да, это input forward iterator для строчки.


K>Внутри есть указатель на данные и булевый флажок ready.


Вместо флажка можно просто обнулять указатель.

K>Собственно мне не нравится то, что пользователь должен знать как именно получить end().

K>Ведь его нельзя попросить у контейнера, как принято для stl контейнеров.

Почему?
Если доменом итератора является строка, то
— либо сделать прокси-контейнер над строкой
— либо сделать функции, конструирующие итератор начала и итератор конца строки
myiter myiter_begin(const char* s) { return myiter(s); }
myiter myiter_end(const char* s) { myiter i(s); while(is_ready(i)) ++i; return i; }
    // может выродиться: return myiter(s + strlen(s));
    // либо возвращаем универсальный конец-ловушку: return myiter(); - а параметр у функции останется в назидание
    // либо конец-ловушку конкретного домена: return myiter(s, end_tag); - специальная сигнатура конструктора

В последнем случае, кстати, можно проверять — принадлежат ли итераторы одному домену. Это полезно для отладки. (Итераторы над разными доменами не просто неравны, а вообще не должны сравниваться!)

K>Мне приходится это писать писать большими буквами в хедере в первых 25 строчках. А пользователю недоступно "естественное" использование итератора, без курения хедера.

K>Вот думаю может функцию-хелпер сделать типа myiter_end()...

Хелпер — дело полезное. Главное, что потом рефакторить будет проще, чем если ты прибьёшь логику гвоздями.

Было бы интересно узнать суть задачи.
Возможно, что ограничение до forward iterator является существенным, а возможно, что и нет.
В первом случае нуль-итератор может быть универсальным концом (как, например, у istream_iterator).
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.