【问题标题】:Is "vector iterator + offset out of range" assertion useful at all?“向量迭代器+偏移超出范围”断言是否有用?
【发布时间】:2014-09-27 14:48:25
【问题描述】:

这个完美的程序在 Visual Studio 2013 的调试模式下失败:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

void main()
{
  vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3};

  for (auto iFrom = v.cbegin(), iTo = iFrom+5; iFrom != v.cend(); iFrom = iTo, iTo += 5)
    cout << *max_element(iFrom, iTo) << '\n';
}

vector iterator + offset out of range 断言失败。它失败是因为iTo &gt; v.cend(),这在这里是无害的。调试器测试没有被取消引用的迭代器的值有什么意义?

顺便说一句,我知道我可以将上面的循环重写为:

for (auto i = v.cbegin(); i != v.cend(); i += 5)
  cout << *max_element(i, i+5) << '\n';

但我试图用一段更复杂的实际代码制作一个简单的例子,其中计算新的迭代器值的计算成本很高。

我也意识到可以更改 _ITERATOR_DEBUG_LEVEL 的值来影响这种行为,但它会在某些库的二进制版本中产生问题,这些库是使用默认调试设置构建的。

【问题讨论】:

    标签: c++ visual-c++ stl visual-studio-debugging


    【解决方案1】:

    这不是无害的...未定义的行为试图将迭代器移过 end(),这是您在第三次也是最后一次迭代中所做的。在使用iTo += 5 执行此操作后立即以iFrom != v.cend() 终止循环而不取消引用迭代器这一事实无关紧要。

    如果确实需要效率,并且您已准备好押注银行的元素数量是 5 的倍数:

    for (auto iFrom = v.cbegin(), iTo = iFrom; iFrom != v.cend(); iFrom = iTo)
    {
        iTo += 5;
        cout << *max_element(iFrom, iTo) << '\n';
    }
    

    【讨论】:

    • 顺便说一句,我准备把整个银行系统都押在元素的数量是 5 的倍数上——这个数字是 10,显然是 5 的倍数;-)
    • @PaulJurczak:我的意思不是在您的硬编码样本向量中,而是在您简化发布代码的任何实际代码中 - 它可能会或可能不会编码。 ;-P 无论如何,即使我在这个行业工作,我也很乐意将整个银行系统打赌,明天凌晨 2 点从东京晴空塔上可以看到彩虹和 3 颗流星,所以我不知道该怎么做打赌……!
    • 我是新手。我正在尝试在“v”中添加一个元素,运行时会崩溃。你能告诉我吗?
    • @Cuanhang.gu:你没有提供足够的信息来告诉你。您应该阅读有关如何使用最少的示例代码发布您自己的问题以重现问题的信息。
    • @TonyD 我说的是基于上面的例子,唯一的修改是在'v'中添加一个元素,使代码如下: void main() { vector v = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3,-1 }; for (auto iFrom = v.cbegin(), iTo = iFrom; iFrom != v.cend(); iFrom = iTo) { iTo += 5; cout stackoverflow.com/questions/43681922/…
    【解决方案2】:

    不完全确定这里的问题是什么,但“重点”是 VS 正试图帮助删除危险代码。是的,原则上,如果您不取消引用 指针 可以指向任何地方,但迭代器是更高级别的抽象,并且能够检测取消引用是否有效,从而引发运行时错误。至少自 VS 2007 年以来,VS 已经使用 vector&lt;T&gt;::iterator 做到了这一点。

    【讨论】:

    • 我的观点是检测解除引用是否有效的能力非常好用,但为什么不只在迭代器时这样做实际上取消引用,而不是之前,当它无关紧要时。
    【解决方案3】:

    max_element() 接受两个迭代器并遍历它们之间的整个范围。如果您考虑一下,如果其中一个迭代器无效,则该范围实际上不是有效的。 SGIMicrosoft 在各自的文档中都提到这是一个先决条件:

    SGI:

    前提条件

    • [first, last) 是有效范围。

    MSDN:

    备注

    • 引用的范围必须有效;所有指针都必须是可解引用的,并且在每个序列中的最后一个位置是 从一开始就可以通过增量到达。

    如果我遇到您的情况,我会在循环的第一步中添加一个检查以查看 iTo 是否仍然有效。如果不是,则将其设置为 v 中的最后一个位置。

    【讨论】:

    • 确实如此,但我从不使用无效范围调用max_element()。问题在于将迭代器递增到 end()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-07
    • 2013-10-11
    • 2018-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多