【问题标题】:Conversion between custom iterator and custom constant iterator自定义迭代器和自定义常量迭代器之间的转换
【发布时间】:2016-04-05 16:04:19
【问题描述】:

我正在开发带有自定义迭代器的通用二维容器。 现在我想为我的iteratorconstant_iterator 类型设置一个begin() 和一个end() 函数。

我的自定义迭代器在我的模板 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_); };
};

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

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

我的const_hiteratorhiterator 都只有一个begin()end() 函数。所以我可以像 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 之间进行某种类型的转换。

【问题讨论】:

  • 旁注:没有稀疏矩阵,大小为 N*M 的一维数组使矩阵实现更容易。
  • 另外,您应该首先正确设置矩阵类。 (析构函数肯定是错误的)
  • 很抱歉,我不确定您的意思。我编辑了我的 Matrix 类代码(添加了 CreateMatrix() 函数),所以如果这就是你的意思,你可以看到我如何在内存中表示我的数据。
  • 忽略上面的cmets,但是你的内存模型太复杂了。删除行数组(storage_type),只剩下一个数组 N*M,也许还有一个运算符 T ()(size_type 行,size_type 列),没有运算符 []。
  • @Superian007 -- Dieter Lücking 指的是让您的矩阵在内部由大小为 N*M 的一维数组表示。这有许多优点。它确保数据紧凑且连续,这对于具有多个缓存级别的现代计算机非常有用,尤其是对于小型矩阵。它使您更容易对阵列进行切片和切块。对于多维数组,数据/视图模型(例如 Blitz++、Eigen)是比 STL 迭代器模型更好的方法。

标签: c++ iterator


【解决方案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->begin() 最终会调用 begin() 的常量或可变版本,具体取决于 objectpointer 是指向可变变量还是 @ 987654324@ 类的实例。

总结:

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

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

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

现在,当然有一个单独的 begin()/end() 实现会很方便。并且没有法律要求要求始终正确支持典型的迭代器语义。

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

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

【讨论】:

    猜你喜欢
    • 2015-02-04
    • 2013-02-17
    • 1970-01-01
    • 2016-06-18
    • 2015-11-19
    • 2013-09-02
    • 1970-01-01
    • 2021-09-15
    相关资源
    最近更新 更多