2014-06-17 39 views
2

我实现了一个迭代器环绕类,它为每一个步骤移动一个基础的random_access_iterator一定量/步幅S包装另一个迭代器的自定义迭代器:迭代通过基础结束迭代器而不检查?

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

它合奏 “每N个元件迭代” 的某种。

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

/* 
    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; 
} 

+0

FYI:这里是[第一部分(http://ericniebler.com/2014/02/16/delimited-ranges/)由Eric Niebler博客文章的一个有趣的意甲(从升压成名)思考当前迭代器设计的问题,它们的局限性以及可能做出的改进。在他的演示过程中,您会发现有趣的策略来为“非典型”范围(过滤范围,无限范围...)构建迭代器。 –

+0

谢谢,非常翔实! – Pixelchemist

回答

2

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

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

+0

我对此有一个疑虑:/ – Pixelchemist

+0

@Pixelchemist你不是第一个。我在不同的时间使用了两种解决方案。 'boost :: filter_iterator'使用第一个(这是唯一适用于任意过滤的工具)。我相信很多其他人也面临这个问题。 –

0

跳转到底层结构,而不是过去的迭代它的真正end的做法,是要求额外的诊断,以能够工作bidirectional或在random access时尚的缺点。

采取问题的operator++

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

对于使用例如矩阵此迭代的第二列与S=3operator++

[包装::开始] = 1 - > 4 - > 7 - > 9 = [包装::结束== 真正end]

现在需要知道如何通过实际列,如果找回自从9-7 != S开始使用或operator--operator[]等。

而是包括“真正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; 
    } 
    // ... 
};