c++ - 自定义迭代器和自定义常量迭代器之间的转换

标签 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 之间进行某种类型的转换。

最佳答案

有一些强逆风在这里抛出一些事件 Spanner 。实际上,出于一个非常简单的原因,自定义容器对于可变迭代器和常量迭代器具有单独的 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->begin() 最终会调用 begin() 的常量或可变版本,具体取决于 object 还是 pointer 是指向类的可变或 const 实例的引用/指针。

总结:

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

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

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

现在,拥有一个 begin()/end() 实现当然会很方便。也不像有法律要求强制一个人始终正确支持典型的迭代器语义。

但是,正确支持这些预期的迭代器语义可以更轻松地利用 C++ 库中的所有算法,并让它们正常工作,而不会出现意外。

当然可以将可变的和常量的 begin() 和 end() 方法声明为私有(private)工厂的包装器,该工厂产生可变的开始或结束迭代器,常量 begin()/end() 外观会降低它的性能在返回之前到常量迭代器。那将是一种可能的方法。这并不理想,因为私有(private)工厂必须是常量方法,才能从常量 begin()/end() 包装器中调用它。

关于c++ - 自定义迭代器和自定义常量迭代器之间的转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34550559/

相关文章:

C++ 随机名称生成器提供重复字符串

c++ - C 和 C++ 中前缀递增运算符的区别

iterator - 切片迭代器能否在恒定时间内前进多个元素?

python - python中的枚举是懒惰的吗?

c++ - 如何在 64 位中构建 Boost 1.64?

c++ - 无法将 std::array 转换为 int?

c++ - 使用 CArray 的新运算符会导致错误

python - 在 Python 文件对象上使用迭代器时是否需要 close()

java - 如何从最后到第一个迭代ArrayList?

c++ - 是否有用于 C++ 的 Lua 表迭代器包装器?