递增迭代器超出范围

Incrementing iterator out of range

本文关键字:范围 迭代器      更新时间:2023-10-16

递增随机访问迭代器超出范围是否违法?事实证明,矢量的Visual C++实现触发了调试断言。

std::vector<int> foo(5);
auto iter = foo.begin();
iter += 10;

只要没有评估内存位置,这对于指针来说应该是合法的。

编辑:显然,即使有指针,这也是非法的。

这是未定义的行为。两者都带有迭代器和指针。具有迭代器,您可能会得到断言失败,至少在迭代器调试已打开。有了指针,它可能会在大多数现代建筑中什么都没有,但已经有了机器它可以在陷阱中触发。你不必访问内存位置本身,只需创建指针,用于未定义的行为发生

编辑:

根据标准(§5.7/5,增加了括号):

当具有整型的表达式被添加到或从中减去时指针,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向从原始元素,使得所得数组元素和原始数组元素等于积分表达式。在里面换句话说,如果表达式P指向数组的第i个元素对象,表达式(P)+N(等价地,N+(P))和(P)-N(其中N值n)分别指向第i+n个和第i−n个数组对象的元素,前提是它们存在。此外,如果表达式P指向数组对象的最后一个元素表达式(P)+1指向数组对象的最后一个元素之后的一个,并且如果表达式Q指向数组的最后一个元素之后的一个对象,表达式(Q)-1指向数组的最后一个元素对象如果指针操作数和结果都指向相同的阵列对象或经过阵列对象的最后一个元素的一个,评估不得产生溢出;否则,行为未定义

随机访问迭代器的相应规则(只有支持添加)分布在几个部分:+=运算符根据重复的++定义(对于语义,它是需要具有恒定的时间复杂度),并且++具有该要求";pre:r是不可引用的。post:r不可引用或r已经过了终点”(来自输入迭代器的定义由前向迭代器继承,后者由双向继承由随机访问迭代器继承的迭代器)。

这是未定义的行为,意味着任何事情都可能发生,包括segfault,或您所经历的,或其他任何事情。基本上,你只是幸运的是它没有坠毁(或者说不幸运,基于观点)。

该语言不需要检查迭代器访问,因为这需要运行时检查。C++通常试图避免不必要的运行时开销,让程序员执行任何必要的检查。

大多数现代平台使用分页虚拟内存,提供粒度为几千字节的内存保护。这意味着在分配的块(例如std::vector管理的块)之后通常有可访问的内存,在这种情况下,超出范围的访问只会践踏该内存。

Visual Studio正试图帮助删除危险代码。原则上,如果不取消引用,指针可以指向任何地方,但迭代器是一种更高级别的抽象,能够检测取消引用是否有效,从而引发运行时错误。Visual Studio至少从VS2007开始就在vector<T>::iterator上做到了这一点。