2015-02-09 114 views
5

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

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

只要内存位置不被评估,这应该是合法的指针。

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

+2

将迭代器维护在范围内的责任完全在于调用者。 – 2015-02-09 11:30:43

+1

是的,这是与指针合法。但是你有什么是迭代器。 – 2015-02-09 11:31:35

+0

@AlexeyAndronov标准说它是未定义的行为。用于迭代器和指针。 – 2015-02-09 11:45:37

回答

2

这是未定义的行为,这意味着可能发生任何事情,包括段错误,或者您遇到过的情况,或其他任何事情。基本上,你只是幸运的没有崩溃(或者不幸,基于观点)。

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

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

Visual Studio正试图帮助删除危险代码。原则上指针可以指向任何地方,如果你没有对其进行解引用,但迭代器是更高级别的抽象,并且能够检测取消引用是否有效,从而引发运行时错误。至少从2007年起,Visual Studio已经完成了vector<T>::iterator

+2

推进迭代器是怎么样的UB?据我所知,topicstarter在他的最后陈述中是正确的 – 2015-02-09 11:38:55

+1

@AlexeyAndronov它是未定义的行为,因为标准说它是未定义的行为,标准库的大多数现代实现将导致断言失败;如果你的没有,并且你正在编译没有优化,请求退款。 – 2015-02-09 11:44:40

+0

@JamesKanze,好的,谢谢,不知道:) – 2015-02-09 11:54:11

3

这是未定义的行为。无论是与迭代器和指针。使用 迭代器,您很可能会得到断言失败,至少在 迭代器调试打开的情况下。有了指针,在大多数现代体系结构中,它可能不会做任何事情,但是有可能在陷阱中触发的机器。您不必访问位置本身的内存 ,只需创建指针,对于未定义的行为即可发生 。

编辑:

从标准(§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 已过时。 ”(来自输入迭代器的定义,其中 由前向迭代器继承,后者由继承自随机访问迭代器的双向迭代器继承)。