自定义迭代器和自定义常量迭代器

时间:2015-12-31 18:53:23

标签: c++ iterator

我正在使用自定义迭代器处理通用二维容器。 现在,我正在尝试为begin()end()类型设置一个iterator和一个constant_iterator功能。

我的自定义迭代器位于我的模板Matrix类中(但为了清晰起见,我将它们单独放在这里)。

template <class T>
class Matrix {

#pragma mark PUBLIC TYPEDEFS
public:
    typedef T value_type;
    typedef std::size_t size_type;
    //typedef typename T::size_type size_type;
    //typedef T::size_type size_type;

#pragma mark -
#pragma mark PRIVATE TYPEDEFS
private:
    typedef T* pointer_type;
    typedef T** storage_type;

   #pragma mark -
#pragma mark PRIVATE VARIABLES
private:
    size_type width_;
    size_type height_;
    storage_type data_;



    // private iterators
    Iterator<T*, T> m_iterator_;
    Iterator<const T*, const T> m_const_iterator_;

    H_Iterator<T*, T> m_hiterator_;
    H_Iterator<const T*, const T> m_const_hiterator_;

#pragma mark -
#pragma mark PUBLIC VARIABLES & TYPEDEFS
public:
    typedef Iterator<T*, T> iterator_type;
    typedef Iterator<const T*, const T> const_iterator_type;

    typedef H_Iterator<T*, T> hiterator;
    typedef H_Iterator<const T*, const T> const_hiterator;

    #pragma mark -
#pragma mark CONSTRUCTORS & DESTRUCTORS
public:
    explicit Matrix(const std::string& fileName) {

    }

    Matrix(const size_type& width, const size_type& height) :   width_(width),
                                                                height_(height),
                                                                data_(CreateMatrix(width, height)),
                                                                m_iterator_(*data_, width, height),
                                                                m_const_iterator_(*data_, width, height),
                                                                m_hiterator_(*data_, width, height),
                                                                m_const_hiterator_(*data_, width, height),                                                                    

        // fill the created matrix with default values of "T"
        for (Matrix<T>::iterator_type it = this->begin(); it != this->end(); ++it)
            *it = T();
    }

    ~Matrix() {
        delete [] data_[0]; // because in data_[0] is array of value_type
        delete [] data_;
    }

    #pragma mark -
#pragma mark PRIVATE METHODS
private:
    storage_type CreateMatrix(const size_type width, const size_type height) {
        storage_type d = new pointer_type[height]; // array with pointers pointing to rows inside the "block"
        pointer_type block = new value_type[width * height]; // one block of memory to store the data

        for (size_type row = 0; row < height; ++row)
            d[row] = &block[row * width];

        return d;
    }

#pragma mark -
#pragma mark PUBLIC METHODS
public:
    hiterator h_begin(size_type row) { return m_hiterator_.begin(row); }
    hiterator h_end(size_type row) { return m_hiterator_.end(row); }
    const_hiterator ch_begin(size_type row) { return m_const_hiterator_.begin(row); }
    const_hiterator ch_end(size_type row) { return m_const_hiterator_.end(row); }

我的内部Iterator类+派生H_Iterator类(H_Iterator类用于从左到右循环遍历一行矩阵)

#pragma mark ITERATOR CLASSES
template <typename P, typename V> // "P" - PointerType; "V" - ValueType
class Iterator : public std::iterator<std::forward_iterator_tag, T> {
protected:
    P itData_;
    size_type w_; // width of the matrix
    size_type h_; // height of the matrix
public:
    Iterator(P d, size_type width, size_type height) : itData_(d), w_(width), h_(height) { }
    Iterator() { }
public:
    V& operator*() const {
        return *itData_;
    }
    Iterator<P, V>& operator++() {
        ++itData_;
        return *this;
    }
    Iterator<P, V>& operator= (T value) {
        *itData_ = value;
        return *this;
    }
    P operator->() {
        return itData_;
    }
    friend bool operator==(const Iterator& lhs, const Iterator& rhs) {
        return !(lhs.itData_ != rhs.itData_);
    }
    friend bool operator!=(const Iterator& lhs, const Iterator& rhs) {
        return !(lhs.itData_ == rhs.itData_);
    }

    Iterator<P, V> begin() { return Iterator<P, V>(itData_, w_, h_); }
    Iterator<P, V> end() { return Iterator<P, V>(itData_ + w_ * h_, w_, h_); };
};

template <typename P, typename V> // "P" - PointerType; "V" - ValueType
class H_Iterator : public Iterator<P, V> {
public:
    H_Iterator(P d, size_type width, size_type height) : Iterator<P, V>(d, width, height) { }
    H_Iterator() { }
public:
    H_Iterator<P, V> begin(size_type row) { return H_Iterator<P, V>(this->itData_ + this->w_ * row, this->w_, this->h_); }
    H_Iterator<P, V> end(size_type row) { return H_Iterator<P, V>(this->itData_ + this->w_ * row + this->w_, this->w_, this->h_); };
};

目前,如果我想使用常量迭代器遍历其中一行,我必须这样做(=我必须使用专为begin制作的endconstant_hiterator函数 - ch_begin()ch_end()):

Matrix<int> m (5, 5);
for (Matrix<int>::const_hiterator hit = m.ch_begin(row); hit != m.ch_end(row); ++hit) {
    cout << *hit << " ";
}

我很难为我的begin()end()提供一个const_hiteratorhiterator功能。所以我可以像std :: vector:

的迭代器一样编写迭代器代码
std::vector<int> vector;
for (std::vector<int>::const_iterator it = vector.begin(); it != vector.end(); ++it) { }
for (std::vector<int>::iterator it = vector.begin(); it != vector.end(); ++it) { }

我认为我应该在hiteratorconst_hiterator之间进行某种转换。

1 个答案:

答案 0 :(得分:1)

有一些沉重的头风在这里扔几把猴子扳手。实际上,自定义容器通常为可变和常量迭代器提供单独的begin()和end()迭代器,这是一个非常简单的原因,下面的例子最好地证明了这一点。此示例演示了C ++库实现的典型容器/迭代器语义,并且通常需要自定义容器/迭代器以相同的方式实现:

class CustomContainer {

public:

     class const_iterator {

        // ...

     };

     class iterator : public const_iterator {

        // ...
     };

     iterator begin();
     iterator end();

     const_iterator begin() const;
     const_iterator end() const;
};

标准容器/迭代器语义不对可变和常量迭代器使用单独的begin()和end()方法。相反,object.begin()或pointer-&gt; begin()最终调用begin()的常量或可变版本,具体取决于objectpointer是否为引用/指针一个mutable或一个const类的实例。

总结:

1)为类的可变实例调用可变迭代器begin()/ end()方法。

2)类的const实例上的begin()/ end()只能返回常量迭代器类型。如果你的begin()/ end()运算符在const类实例上调用时会返回可变迭代器,那么这就可以通过简单地实例化它的可变迭代器来修改类的const实例!

3)强烈希望可变迭代器是const迭代器的子类。这是自动支持将可变迭代器传递给函数或仅需要const迭代器参数的方法的最简单方法(也可以通过定义和实现重载转换操作符来实现,但使用子类更容易,并且通常会带来更好的表现。)

现在,确实有一个begin()/ end()实现会很方便。并且它的法律要求并不像要求一个人总是正确地支持典型的迭代器语义。

但是,正确地支持这些预期的迭代器语义使得利用C ++库中的所有算法变得更加容易,并使它们正常工作,没有任何意外。

当然可以将可变和常量begin()和end()方法声明为包含生成可变开头或结束迭代器的私有工厂的包装器,并使用常量begin()/ end()外观降级它返回之前到常量迭代器。这将是一种可能的方法。它并不理想,因为私有工厂必须是一个常量方法,以便从常量begin()/ end()包装器中调用它。