【问题标题】:Custom iterator wrapping another iterator: iterating past the underlying end iterator without checking?包装另一个迭代器的自定义迭代器:在不检查的情况下迭代底层结束迭代器?
【发布时间】:2014-08-07 12:18:39
【问题描述】:

我实现了一个迭代器包装类,它移动底层random_access_iterator 一定数量/步幅S,每走一步。

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

它集合了某种“每 Nth 个元素迭代器”。

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

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

当 S 为 4 时,我们可以使用 Wrapper [Wrapper::begin]=0 -&gt; 4 -&gt; 8 -&gt; 12=[Wrapper::end] 或使用 S=3 [Wrapper::begin]=1 -&gt; 4 -&gt; 7 -&gt; 10=[Wrapper::end] 的第二列迭代对角线 它几乎可以解决end 迭代器的问题。生成的end() 迭代器可能是&gt; 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;
}

?

【问题讨论】:

  • 仅供参考:这里是 the first part Eric Niebler(来自 Boost 名声)的一系列有趣的博客文章,他思考了当前迭代器设计的问题、它们的局限性以及可以做出的改进。在他的演示过程中,您会发现为“非典型”范围(过滤范围、无限范围……)构建迭代器的有趣策略
  • 谢谢,信息量很大!

标签: c++ iterator


【解决方案1】:

您几乎已经找到了解决方案;由于 STL 迭代器的设计不佳,您想要的迭代器需要同时包含当前和结束迭代器。

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

【讨论】:

  • 我对此有所顾虑:/
  • @Pixelchemist 你不是第一个。我在不同的时间使用了这两种解决方案。 boost::filter_iterator 使用第一个(这是唯一可用于任意过滤的)。我相信很多其他人也面临过这个问题。
【解决方案2】:

跳转到底层结构的真实end而不是迭代它的方法,具有需要额外诊断才能工作bidirectional或@987654323的缺点@时尚。

提问operator++:

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

对于示例矩阵,它使用S=3 使用operator++ 迭代第二列

[Wrapper::begin] = 1 -> 4 -> 7 -> 9 = [Wrapper::end == real end]

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

end 迭代器不包括需要额外信息才能“双向”(或以随机访问方式)行走的 'real' 迭代器,而 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; 
  }
  // ...
};

【讨论】:

    猜你喜欢
    • 2019-01-12
    • 2016-06-18
    • 2016-04-09
    • 2015-06-17
    • 1970-01-01
    • 2013-06-17
    • 2010-10-09
    • 1970-01-01
    • 2018-09-23
    相关资源
    最近更新 更多