Код для базового итератора с произвольным доступом на основе указателей?

Я никогда не реализовывал итераторы, подобные STL, и пытаюсь понять, как реализовать очень простые вещи, основанные на указателях. Когда у меня будет этот класс, я смогу модифицировать его, чтобы делать более сложные вещи. Следовательно, это первый шаг, и мне нужно, чтобы он был твердым, чтобы понять, как писать свои собственные итераторы (без повышения).

Я написал следующий код и знаю, что в нем есть ошибки. Можете ли вы помочь мне правильно спроектировать класс итератора произвольного доступа, вдохновленный этим:

template<Type> class Container<Type>::Iterator : public std::iterator<random_access_iterator_tag, Type>
{
    // Lifecycle:
    public:
        Iterator() : _ptr(nullptr) {;}
        Iterator(Type* rhs) : _ptr(rhs) {;}
        Iterator(const Iterator &rhs) : _ptr(rhs._ptr) {;}

    // Operators : misc
    public:
        inline Iterator& operator=(Type* rhs) {_ptr = rhs; return *this;}
        inline Iterator& operator=(const Iterator &rhs) {_ptr = rhs._ptr; return *this;}
        inline Iterator& operator+=(const int& rhs) {_ptr += rhs; return *this;}
        inline Iterator& operator-=(const int& rhs) {_ptr -= rhs; return *this;}
        inline Type& operator*() {return *_ptr;}
        inline Type* operator->() {return _ptr;}
        inline Type& operator[](const int& rhs) {return _ptr[rhs];}

    // Operators : arithmetic
    public:
        inline Iterator& operator++() {++_ptr; return *this;}
        inline Iterator& operator--() {--_ptr; return *this;}
        inline Iterator& operator++(int) {Iterator tmp(*this); ++_ptr; return tmp;}
        inline Iterator& operator--(int) {Iterator tmp(*this); --_ptr; return tmp;}
        inline Iterator operator+(const Iterator& rhs) {return Iterator(_ptr+rhs.ptr);}
        inline Iterator operator-(const Iterator& rhs) {return Iterator(_ptr-rhs.ptr);}
        inline Iterator operator+(const int& rhs) {return Iterator(_ptr+rhs);}
        inline Iterator operator-(const int& rhs) {return Iterator(_ptr-rhs);}
        friend inline Iterator operator+(const int& lhs, const Iterator& rhs) {return Iterator(lhs+_ptr);}
        friend inline Iterator operator-(const int& lhs, const Iterator& rhs) {return Iterator(lhs-_ptr);}

    // Operators : comparison
    public:
        inline bool operator==(const Iterator& rhs) {return _ptr == rhs._ptr;}
        inline bool operator!=(const Iterator& rhs) {return _ptr != rhs._ptr;}
        inline bool operator>(const Iterator& rhs) {return _ptr > rhs._ptr;}
        inline bool operator<(const Iterator& rhs) {return _ptr < rhs._ptr;}
        inline bool operator>=(const Iterator& rhs) {return _ptr >= rhs._ptr;}
        inline bool operator<=(const Iterator& rhs) {return _ptr <= rhs._ptr;}

    // Data members
    protected:
        Type* _ptr;
};

Большое Вам спасибо.


person Vincent    schedule 23.08.2012    source источник
comment
Какие ошибки? Ошибки компилятора? Ошибки компоновщика? Ошибки времени выполнения? Логические ошибки? Что-то другое?   -  person Some programmer dude    schedule 23.08.2012
comment
Я знаю, что есть ошибки - это какой-то тест? Я не думаю, что SO - подходящий сайт для этого ...   -  person Kerrek SB    schedule 23.08.2012
comment
Указатель - это итератор. Какова цель обертывания его классом?   -  person Pete Becker    schedule 23.08.2012
comment
Цель состоит в том, чтобы понять, как правильно реализовать класс итератора (в частности, сигнатуры функций и то, что они делают).   -  person Vincent    schedule 23.08.2012
comment
Ну, вам действительно не нужно public повсюду, но поскольку у вас нет в них элементов данных, это не имеет значения. return Iterator(_ptr+rhs); теоретически создает лишний ненужный временный объект, вы могли бы просто return _ptr+rhs;.   -  person BoBTFish    schedule 23.08.2012
comment
За исключением операторов присваивания (включая +=, -=), все операторы должны быть функциями-членами с квалификацией const.   -  person James McNellis    schedule 24.08.2012


Ответы (3)


В целом ваш подход правильный. Оператор постфиксного увеличения / уменьшения должен возвращаться по значению, а не по ссылке. Еще я сомневаюсь:

Iterator(Type* rhs) : _ptr(rhs) {;}

Это говорит всем, что этот класс итератора реализован на основе указателей. Я бы попробовал сделать этот метод вызываемым только контейнером. То же самое для присвоения указателю. Добавление двух итераторов для меня не имеет смысла (я бы оставил "iterator + int"). Вычитание двух итераторов, указывающих на один и тот же контейнер, может иметь некоторый смысл.

person Alexander Chertov    schedule 23.08.2012
comment
По его словам, это обучающее упражнение, поэтому он делает все возможное. Я тоже был удивлен operator[], но он есть и для итераторов с произвольным доступом! en.cppreference.com/w/cpp/concept/RandomAccessIterator - person BoBTFish; 23.08.2012
comment
Я считаю, что вам нужен inline difference_type operator-(const Iterator&) вместо inline Iterator operator-(const Iterator&). Я не думаю, что вам нужно то же самое для operator+. Некоторые алгоритмы (например, std::sort) не работают без difference_type operator-. У вас не может быть и того, и другого, потому что различаются только возвращаемые типы. - person greg; 14.02.2014

В вашем коде есть следующие проблемы:

  • Вы не соблюдаете правило трех / пяти. Лучший вариант в вашей ситуации - не объявлять какие-либо настраиваемые деструкторы, конструкторы копирования / перемещения или операторы присваивания копирования / перемещения. Давайте следовать так называемому правилу нуля.
  • Iterator(Type* rhs) может быть личным, а Container может быть помечен как друг Iterator, но это не обязательно.
  • operator=(Type* rhs) - плохая идея. Безопасность типов не в этом.
  • Пост-ин (де) кремация должна возвращать Iterator, а не Iterator &.
  • Добавление двух итераторов не имеет смысла.
  • Вычитание двух итераторов должно возвращать разницу, а не новый итератор.
  • Вы должны использовать std::iterator<std::random_access_iterator_tag, Type>::difference_type вместо const int &.
  • Если метод не изменяет объект, он должен быть помечен как const.

Полезный ресурс: RandomAccessIterator @ cppreference.com

Вот фиксированная версия вашего кода:

template<typename Type>
class Container<Type>::Iterator : public std::iterator<std::random_access_iterator_tag, Type>
{
public:
    using difference_type = typename std::iterator<std::random_access_iterator_tag, Type>::difference_type;

    Iterator() : _ptr(nullptr) {}
    Iterator(Type* rhs) : _ptr(rhs) {}
    Iterator(const Iterator &rhs) : _ptr(rhs._ptr) {}
    /* inline Iterator& operator=(Type* rhs) {_ptr = rhs; return *this;} */
    /* inline Iterator& operator=(const Iterator &rhs) {_ptr = rhs._ptr; return *this;} */
    inline Iterator& operator+=(difference_type rhs) {_ptr += rhs; return *this;}
    inline Iterator& operator-=(difference_type rhs) {_ptr -= rhs; return *this;}
    inline Type& operator*() const {return *_ptr;}
    inline Type* operator->() const {return _ptr;}
    inline Type& operator[](difference_type rhs) const {return _ptr[rhs];}

    inline Iterator& operator++() {++_ptr; return *this;}
    inline Iterator& operator--() {--_ptr; return *this;}
    inline Iterator operator++(int) const {Iterator tmp(*this); ++_ptr; return tmp;}
    inline Iterator operator--(int) const {Iterator tmp(*this); --_ptr; return tmp;}
    /* inline Iterator operator+(const Iterator& rhs) {return Iterator(_ptr+rhs.ptr);} */
    inline difference_type operator-(const Iterator& rhs) const {return Iterator(_ptr-rhs.ptr);}
    inline Iterator operator+(difference_type rhs) const {return Iterator(_ptr+rhs);}
    inline Iterator operator-(difference_type rhs) const {return Iterator(_ptr-rhs);}
    friend inline Iterator operator+(difference_type lhs, const Iterator& rhs) {return Iterator(lhs+rhs._ptr);}
    friend inline Iterator operator-(difference_type lhs, const Iterator& rhs) {return Iterator(lhs-rhs._ptr);}

    inline bool operator==(const Iterator& rhs) const {return _ptr == rhs._ptr;}
    inline bool operator!=(const Iterator& rhs) const {return _ptr != rhs._ptr;}
    inline bool operator>(const Iterator& rhs) const {return _ptr > rhs._ptr;}
    inline bool operator<(const Iterator& rhs) const {return _ptr < rhs._ptr;}
    inline bool operator>=(const Iterator& rhs) const {return _ptr >= rhs._ptr;}
    inline bool operator<=(const Iterator& rhs) const {return _ptr <= rhs._ptr;}
private:
    Type* _ptr;
};
person cubuspl42    schedule 07.08.2015
comment
Iterator operator++(int) const - не может быть константой - person Dewfy; 27.11.2015

Посмотрите, как это делает Boost, итераторы в boost / container /vector.hpp - vector_const_iterator и vector_iterator достаточно легко понять итераторы, основанные на указателях.

person Silas Parker    schedule 23.08.2012