Форум программистов, компьютерный форум CyberForum.ru

Итераторы и итерация. Оператор >>. Простой текстовый редактор Страуструпа - C++

Восстановить пароль Регистрация
Другие темы раздела
C++ Друзья, подскажите, можно ли дружественную функцию сделать виртуальной? http://www.cyberforum.ru/cpp-beginners/thread962752.html
Допустим есть какой-то базовый класс в котором объявлена дружественная функция, а определена она в глобальной области. Можно ли эту дружественную функцию сделать виртуальной, и скажем из производного класса запустить ее. Приведите пожалуйста код, как это делается! Заранее спасибо!
C++ Целочисленная арифметика Нужно переставить старшую и младшую цифры в записи натурального числа. Не могу понять как это сделать http://www.cyberforum.ru/cpp-beginners/thread962728.html
C++ Указатель и амперсанд
Всем здрасьте. У меня тут возник вопрос. Приведу простой примерчик двух функций(не смотрите на ошибки если есть , дело не в них) void Calculate(int*,int*); void main() { int one = 1; int two = 2;
C++ Преобразование кода для Visual C++
Дана задача:В текстовом файле хранится база отдела кадров предприятия. На предприятии 100 сотрудников. Каждая строка файла содержит запись об одном сотруднике. Формат записи: фамилия и инициалы (30 позиций, фамилия должна начинаться с первой позиции), год рождения (5 позиций), оклад (10 позиций). Написать программу, которая по заданной фамилии выводит на экран сведения о сотруднике,...
C++ Проблеммка с конструктором копирования http://www.cyberforum.ru/cpp-beginners/thread962714.html
В общем суть: /*Создать класс - одномерный массив целых чисел (вектор). Функции-члены обращаются к отдельному элементу массива, вывода массива на экран, поэлементного сложения и вычитания со скаляром, вывод элемента по заданному индексу.*/ #pragma once class Vector { int size; int **arr; public:
C++ Как заполнить трехмерный массив случайными числами Добрый день, товарищи! Подскажите как заполнить трёхмерный массив случайными числами имеется код: int ***arr = new int**; for(int i=0;i<x;i++) { arr=new int*; подробнее

Показать сообщение отдельно
Cynacyn
 Аватар для Cynacyn
33 / 33 / 0
Регистрация: 02.05.2013
Сообщений: 109
26.09.2013, 12:21     Итераторы и итерация. Оператор >>. Простой текстовый редактор Страуструпа
Добрый день!
Есть код Страуструпа из Принципы и практика использования С++ Глава 20, параграф 6.
Код описывает простой текстовой редактор. Строка символов заканчивающаяся '\n' хранятся в std::vector<char>, строки хранятся в std::list - и всё это класс Document. Для того чтобы иметь возможно следовать по символам от первого до последнего не беспокоясь о разделении на строки разработан итератор Text_iterator. Схема во вложении.
Код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
typedef vector<char> Line;
 
//-------------------------------------------------------
 
class Text_iterator {
    list<Line>::iterator ln;
    Line::iterator pos;
public:
    Text_iterator(list<Line>::iterator ll, Line::iterator pp)
        :   ln(ll), pos(pp) {}
    
    char& operator*() { return *pos; }
    
    Text_iterator& operator++() {
        if(pos==ln->end()) {
            ++ln;
            pos=ln->begin();
        }
        ++pos;
        return *this;
    }
 
    bool operator==(const Text_iterator& other) const {
        return ln==other.ln && pos==other.pos;
    }
    bool operator!=(const Text_iterator& other) const {
        return !(*this==other);
    }
};
 
//-------------------------------------------------------
 
struct Document {
    list<Line> line;
    Document() { line.push_back(Line()); }
 
    Text_iterator begin() {
        return Text_iterator(line.begin(), line.begin()->begin()); 
    }
    Text_iterator end() {
        return Text_iterator(line.end(), line.end()->end()); 
            
    }
};
//-------------------------------------------------------
 
istream& operator>>(istream& is, Document& d) 
{
    char ch;
    while(is>>ch) {
        d.line.back().push_back(ch);
        if(ch=='\n')
            d.line.push_back(Line());
    }
    return is;
}
//-------------------------------------------------------
при попытке скомпилировать код
C++
1
2
3
4
5
6
7
8
9
Document d;
    
    fstream fs("text.txt",1);
    if(!fs) throw runtime_error("can't open text.txt");
    fs>>d;
    fs.close();
    
    for(Text_iterator it=d.begin(); it!=d.end();++it)
        cout <<*it;
вылетает ошибка
Expression: list iterator not dereferencable
ошибка содержится в строка 41-44
C++
1
2
3
4
 Text_iterator end() {
        return Text_iterator(line.end(), line.end()->end()); 
            
    }
а именно в выражении line.end()->end(), насколько я понимаю итератор, возвращаемый методом end() нельзя разыменовать, т.к. он указывает на воображаемый элемент, следующий за последним элементом последовательности. Логически понятно, что хотел сделать Страуструп - в качестве второго параметра ( то что подразумевалось под line.end()->end()) ему нужен был .end() последнего элемента списка. (см. вложение).
Меняю представление Text_iterator Text_iterator::end() :
C++
1
2
3
4
5
6
7
8
9
10
11
12
    Text_iterator end() {
        //return Text_iterator(line.end(), line.end()->end());  // Expression: list iterator not dereferencable
 
        list<Line>::iterator last_line = line.begin();
        list<Line>::iterator it=line.begin();
        it++;
        for(; it!=line.end(); it++, last_line++);
 
        return Text_iterator(
            line.end(), 
            last_line->end()); 
    }
Теперь выводит текст, но в конце вылетает ошибка:

Expression: vector iterator not dereferencable
Судя по всему ошибка в строках 15-22:
C++
1
2
3
4
5
6
7
8
    Text_iterator& operator++() {
        if(pos==ln->end()) {
            ++ln;
            pos=ln->begin();
        }
        ++pos;
        return *this;
    }
Итератор pos указывает на Line::end(), но проверка в main(): it!=d.end() не обрабатывается, потому что итератор ln не указывает на list<Line>::end(). То есть по идее сначала нужно увеличивать pos, а потов проверять не указывает ли он на end(), а потом увеличивать ln, если нужно. Меняю представление Text_iterator& operator++():
C++
1
2
3
4
5
6
7
8
    Text_iterator& operator++() {
        ++pos;
        if(pos==ln->end()) {
            ++ln;
            pos=ln->begin();
        }
        return *this;
    }
Теперь опять вылетает ошибка:
Expression: list iterator not dereferencable
Ошибка в предыдущем листинге Text_iterator& operator++() - строка 5: ln указывает на list<Line>::end(), то есть для него нельзя вызвать метод begin().

Теперь вопросы:
1. Скажите пожалуйста, как проверить равенство some_stl_conteiner<some_class>::iterator it == some_stl_conteiner<some_class>::end не имея конкретного объекта. То есть узнать, не является ли итератор концом последовательности, не имея доступа к самой последовательности? Или необходимо сделать класс Text_iterator вложенным в класс Document, чтобы методы итератора имели доступ к данным line - могли проверять себя на равенство line.end().

2. Оператор ввода для класса Document (строки 48-57 самого первого листинга), работает не так как ожидалось. Он игнорирует любые разделители. Насколько я понимаю, для того чтобы он работал корректно нужно считывать символы чем-то вроде get?

Заранее, спасибо (:
Миниатюры
Итераторы и итерация. Оператор >>. Простой текстовый редактор Страуструпа  
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
 
Текущее время: 16:24. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru