增加随机访问迭代器超出范围是否违法? 事实证明,矢量的Visual C++实现会触发调试断言。增加迭代器超出范围
std::vector<int> foo(5);
auto iter = foo.begin();
iter += 10;
只要内存位置不被评估,这应该是合法的指针。
编辑:显然它是非法的,即使有指针。
增加随机访问迭代器超出范围是否违法? 事实证明,矢量的Visual C++实现会触发调试断言。增加迭代器超出范围
std::vector<int> foo(5);
auto iter = foo.begin();
iter += 10;
只要内存位置不被评估,这应该是合法的指针。
编辑:显然它是非法的,即使有指针。
这是未定义的行为,这意味着可能发生任何事情,包括段错误,或者您遇到过的情况,或其他任何事情。基本上,你只是幸运的没有崩溃(或者不幸,基于观点)。
该语言不需要迭代器访问来检查,因为这需要运行时检查。 C++通常会尝试避免不必要的运行时间开销,让程序员执行任何必要的检查。
大多数现代平台都使用分页虚拟内存,提供内存保护,粒度为几千字节。这意味着在分配的块(如由std :: vector管理的块)之后通常会有可访问的内存,在这种情况下,超出范围的访问只会在该内存上跺脚。
Visual Studio正试图帮助删除危险代码。原则上指针可以指向任何地方,如果你没有对其进行解引用,但迭代器是更高级别的抽象,并且能够检测取消引用是否有效,从而引发运行时错误。至少从2007年起,Visual Studio已经完成了vector<T>::iterator
。
推进迭代器是怎么样的UB?据我所知,topicstarter在他的最后陈述中是正确的 – 2015-02-09 11:38:55
@AlexeyAndronov它是未定义的行为,因为标准说它是未定义的行为,标准库的大多数现代实现将导致断言失败;如果你的没有,并且你正在编译没有优化,请求退款。 – 2015-02-09 11:44:40
@JamesKanze,好的,谢谢,不知道:) – 2015-02-09 11:54:11
这是未定义的行为。无论是与迭代器和指针。使用 迭代器,您很可能会得到断言失败,至少在 迭代器调试打开的情况下。有了指针,在大多数现代体系结构中,它可能不会做任何事情,但是有可能在陷阱中触发的机器。您不必访问位置本身的内存 ,只需创建指针,对于未定义的行为即可发生 。
编辑:
从标准(§5.7/ 5,emphesis加):
当具有整体式的表达式添加到或从 减去一个指针,其结果有指针操作数的类型。如果 指针操作数指向数组对象的元素,并且数组 足够大,则结果指向与原始元素偏移的元素,以使得结果数组元素和原始数组元素的下标之差等于积分表达。换言之,如果表达式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 已过时。 ”(来自输入迭代器的定义,其中 由前向迭代器继承,后者由继承自随机访问迭代器的双向迭代器继承)。
将迭代器维护在范围内的责任完全在于调用者。 – 2015-02-09 11:30:43
是的,这是与指针合法。但是你有什么是迭代器。 – 2015-02-09 11:31:35
@AlexeyAndronov标准说它是未定义的行为。用于迭代器和指针。 – 2015-02-09 11:45:37