Пользовательский итератор не разыменовывает проблему

Вот первая попытка реализации итератора для std::list<std::vector<char>>:

Document.h

#ifndef Document_h
#define Document_h

//-------------------------------------------------------------------------

typedef std::vector<char> Line;                                 // line of text

//-------------------------------------------------------------------------

class Text_iterator
{
public:
Text_iterator(std::list<Line>::iterator l, Line::iterator p)// constructor
: ln(l), pos(p) { }

Text_iterator(const Text_iterator& src)                     // copy constructor
: ln(src.ln), pos(src.pos) { }

Text_iterator& operator= (const Text_iterator& src)         // copy assignment
{
Text_iterator temp(src);
this->swap(temp);
return *this;
}

char& operator*() { return *pos; }                          // dereferencing

Text_iterator& operator++ ()                                // incrementation
{
++pos;
if (pos == ln->end())
{
++ln;
pos = ln->begin();
}
return *this;
}

bool operator== (const Text_iterator& other) const          // comparison
{
return ln == other.ln && pos == other.pos;
}

bool operator != (const Text_iterator& other) const         // comparison
{
return !(*this == other);
}

void swap(Text_iterator& src)                               // helper: swap
{
std::swap(src.get_line(), ln);
std::swap(src.get_column(), pos);
}

std::list<Line>::iterator get_line() { return ln; }         // accessors
Line::iterator get_column() { return pos; }

private:
std::list<Line>::iterator ln;                               // data members
Line::iterator pos;
};

//-------------------------------------------------------------------------

void swap (Text_iterator& lhs, Text_iterator& rhs)              // object swap
{
lhs.swap(rhs);
}

//-------------------------------------------------------------------------

class Document
{
public:
typedef Text_iterator iterator;
public:
Document()                                                  // constructor
{
Line l(10, 'a');
text.push_back(l);
}

iterator begin()                                            // iterator to first element
{
return iterator(text.begin(), (*text.begin()).begin());
}

iterator end()                                              // iterator to last element
{
return iterator(text.end(), (*text.end()).end());
}

void print()
{
for (Document::iterator p = begin(); p != end(); ++p)
{
std::cout << *p;
getchar();
}
}

std::list<Line> text;                                       // data member
};

#endif

main.cpp

#include <iostream>
#include <sstream>
#include <vector>
#include <list>
#include <algorithm>
#include "Document.h"
int main()
{
Document text;
text.print();
}

Ожидаемый результат:

аааааааааа

Вместо ожидаемого результата я получаю:

Ошибка отладки утверждения
Выражение: итератор списка не разыменовывается.

Почему у меня такое поведение и как его исправить?


Примечание: после краткого исследования я обнаружил, что наиболее частой причиной такого поведения является попытка разыменования end() итератор, но я не могу найти такое выражение в моем коде.

0

Решение

Вы разыменовываете конечный итератор *text.end() в Document::end(), Самая простая вещь, которую можно исправить, это использовать list::back() (а также list::front() в Document::begin()).

Когда вы исправите это, вы обнаружите, что Text_iterator::operator++ также разыменовывает конечный итератор, так как вы не проверяете ln против соответствующего конца. @Джонатан Поттер комментарий прав, вам нужно пройти text.end() как для Text_iterators

Изменения:

class Text_iterator
{
// Declarations elided
private:
std::list<Line>::iterator ln;
std::list<Line>::iterator ln_end;
Line::iterator pos;
}

Text_iterator::Text_iterator(std::list<Line>::iterator l, std::list<Line>::iterator l_end, Line::iterator p)
: ln(l), ln_end(l_end), pos(p) { }

Text_iterator::Text_iterator(const Text_iterator& src)
: ln(src.ln), ln_end(src.ln_end), pos(src.pos) { }

Text_iterator& Text_iterator::operator++ ()
{
++pos;
if (pos == ln->end())
{
++ln;
if(ln != ln_end)
{
pos = ln->begin();
}
}
return *this;
}

void Text_iterator::swap(Text_iterator& src)
{
std::swap(src.ln, ln);
std::swap(src.ln_end, ln_end);
std::swap(src.pos, pos);
}

Document::iterator Document::begin()
{
return iterator(text.begin(), text.end(), text.front().begin());
}

Document::iterator Document::end()
{
return iterator(text.end(), text.end(), text.back().end());
}

Когда произойдет окончательное приращение, pos укажет конечный итератор последнего Lineи ln укажет конечный итератор текста, который мы передали Text_iterator конструктор в Document::end(), Нам не нужно сравнивать или выставлять Text_iterator::ln_end сохранить разумную семантику.

1

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

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector