【问题标题】:How to handle checked iterators?如何处理已检查的迭代器?
【发布时间】:2014-05-07 10:32:19
【问题描述】:

对于 VS2013 中的调试模式,如果我向迭代器添加一个常量值并且该迭代器之后将超出范围,则会收到超出范围的异常。

例如:

#include <cstdlib>
#include <vector>

int main(void) {
    std::vector<unsigned char> data(10, 0);

    auto it = data.begin();

    while (it != data.end()) {
        if ((it + 3) <= data.end()) {
            it += 3;
        }
        else {
            it = data.end();
        }
    }

    return EXIT_SUCCESS;
}

while-loop 的第四次运行中,检查it + 3 &lt;= data.end() 失败并抛出异常。

VS 编译器的一个简短解决方法是插入 #define _ITERATOR_DEBUG_LEVEL 0,以在调试模式下禁用检查迭代器的选项。

但我希望有一个更好、更通用的解决方案,它适用于 VS 和 GCC 编译器! 我确信 STL 已经存在一种方法来处理迭代器距离和这样的检查:) 但我还不知道......

【问题讨论】:

  • 为什么不for (auto it = data.begin(); std::distance(it, data.end()) &gt; 3; it += 3){//your loop}
  • 第一个元素之前或最后一个元素之后的迭代器 + 1 是未定义的行为。 (请注意,仅获取此迭代器——即使没有取消引用它——也是 UB)
  • 注意:编译器的抱怨是因为你在做一些“非法”的事情,这只是一个症状,因此你的解决方法并不是真正的:你交易的是一个易于理解且可重现的未定义集合的症状。

标签: c++ iterator


【解决方案1】:

更好的常见解决方案如下

while ( std::distance( it, data.end() ) >= 3 )
{
    // some code
    std::advance( it, 3 );
    // some code
}

或者

while ( it != data.end() )
{
    // some code
    std::advance( it, std::min<int>( 3, std::distance( it, data.end() ) ) );
    // some code
}

这两种变体之间的选择取决于您是否希望至少处理一次迭代器,即使 data.end() - 它小于 3。

如果使用非随机访问迭代器,则循环可以看起来像

while ( it != data.end() )
{
    // some code
    ( ++it != data.end() ) && ( ++it != data.end() ) && ( ++it != data.end() );
    // some code
}

【讨论】:

  • while ( std::distance( it, data.end() ) &gt;= 3 ) 也许?
  • 完美,就是这样!非常感谢:)。
  • 虽然在非 RandomAccessIterators 上这有点效率低下,因为你最终会从itmin(end, it+3) 两次:一次用于distance,一次用于advance。因此,在这些情况下,“检查”预付款会更有效。
  • @Matthieu M 我同意你的看法。在非随机访问迭代器的情况下,循环体应包含表达式 ( ++it != data.end() ) && ( ++it != data.end() ) && ( ++it != data.结束());
【解决方案2】:

这是因为end() 指向元素超出向量的最后一个实际元素。所以你的条件if ((it + 3) &lt;= data.end()) 最终将评估为end() + 1(当it 已经等于end()),这是无效的。要修复它,请将其更改为 if ((it + 3) &lt; data.end())

重申:向量或任何其他 STL 容器的最后一个可用元素位于 end() - 1。如果容器为空,begin()end() 相同。取消引用指向end() 的迭代器总是错误的。

【讨论】:

  • 不,这没有什么区别。所以我知道过去的结束迭代器指向最后一个之外的元素。但是为了比较,只有迭代器/(指针)指向的地址应该是相关的。所以我认为 end() 返回的迭代器在我的情况下永远不会被取消引用。
  • 错误:it+3it==end()-1 时同样无效。
  • @MSalters:这就解释了为什么我的解决方案没有帮助。
猜你喜欢
  • 2016-04-09
  • 2012-03-26
  • 2011-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-20
  • 1970-01-01
  • 2012-03-14
相关资源
最近更新 更多