自定义迭代器包装另一个迭代器:迭代通过底层的结束迭代器而不检查?

时间:2014-06-17 13:04:29

标签: c++ iterator

我实现了一个迭代器包装类,它将每个步骤的基础random_access_iterator移动一定量/步长S

Wrapper<Iterator> + i === Iterator + i*S

它集合了某种“每N th 元素迭代器”。

基本思想是迭代连续存储矩阵的列或对角线:

/*
    0  1  2
    3  4  5
    6  7  8
*/

当S为4时,我们可以使用Wrapper [Wrapper::begin]=0 -> 4 -> 8 -> 12=[Wrapper::end]或使用S=3 [Wrapper::begin]=1 -> 4 -> 7 -> 10=[Wrapper::end]的第二列迭代对角线 它几乎与end迭代器的问题一起使用。生成的end()迭代器可能是> last+1(UB?)。

如果检查的迭代器与Wrapper一起使用,则会失败,因为它们将检测到最后一步超出基础迭代范围的有效范围[begin,end]

除了使Wrapper本身成为某种检查迭代器,即包含对有效end的引用之外,是否有任何理智,高效的方法来解决这个问题:

Wrapper<Iterator> & operator++ ()
{ 
  m_it += std::min(S, std::distance(m_it, m_end));
  return *this;
}

Wrapper<Iterator> & operator++ ()
{ 
  m_it += S;
  return *this;
}

2 个答案:

答案 0 :(得分:2)

你几乎找到了解决方案;由于STL迭代器的设计很差,所需的迭代器需要包含当前迭代器和结束迭代器。

如果唯一的应用程序迭代在连续存储的矩阵上,并且迭代器本身绑定到矩阵(例如列迭代器),并且矩阵不是太大,那么您可以简单地确保有一个底层连续内存中的附加行,例如对于4x4矩阵,分配20个条目。

答案 1 :(得分:0)

跳转到底层结构的真实 end而不是迭代它的方法,有一个缺点,需要额外的诊断才能工作bidirectional或以random access方式。

问问题operator++

Wrapper<Iterator> & operator++ ()
{ 
  m_it += std::min(S, std::distance(m_it, m_end));
  return *this;
}

对于示例矩阵,使用S=3

使用operator++迭代第二列

[Wrapper :: begin] = 1 - &gt; 4 - &gt; 7 - &gt; 9 = [Wrapper :: end == real end]

现在,如果operator-使用operator--operator[]9-7 != S等,则需要知道如何返回实际列。

而不是包含'真实'end迭代器,它需要额外的信息才能行走'双向'(或以随机访问方式),Wrapper迭代器可以增加偏移O而不是底层迭代器本身,并且只在解除引用时推进迭代器。

template<class BaseIterator,
  typename std::enable_if<
    std::is_same<
      typename BaseIterator::iterator_category, 
      std::random_access_iterator_tag
    >::value
  >::type * = 0>
class RASItWrapper 
  : public std::iterator_traits<BaseIterator>
{
  BaseIterator m_it;
  difference_type S, O;
public:
  // ...
  RASItWrapper & operator++ ()
  { // increment then return
    O += S;
    return *this;
  }
  // ...
  reference operator* () const { return *(m_it + O); }
  pointer   operator->() const { return (m_it + O).operator->(); }
  reference operator[] (difference_type const & i) const
  {
    return (m_it + O)[i*N];
  }
  // ...
  bool operator== (RASItWrapper const &rhs) const 
  { // perhaps only compare O since comparing different ranges is meaningless
    return m_it == rhs.m_it && O == rhs.O; 
  }
  // ...
};