为什么使用`std :: reverse_iterator`不会调用UB?

时间:2014-08-19 21:09:26

标签: c++ stl iterator

我今天正在与std::reverse_iterator合作,并考虑如何使用在容器上调用begin创建的值。根据{{​​3}},如果我reverse_iterator r构建了iterator i,则以下内容必须保留&*r == &*(i-1)

然而,这意味着如果我写这个

std::vector<int> vec = {1, 2, 3, 4, 5};
auto iter = std::make_reverse_iterator(begin(vec));

iter现在指向放在begin(vec)之前的一块内存,这是一个超出范围的内存。通过严格解释C ++标准,这将调用UB。

(指针/迭代器有一个特定的规定,指向数组的1-last-the-end-end,但据我所知,没有指针/迭代器指向元素1-ahead-of-the-数组的开头。)

那么,我是否正在阅读cppreference错误,或者本案例标准中是否有特定条款,或者在使用reverse_iterator时,整个数组被视为反向和这样,指向数组前面的指针实际上是指针结束了吗?

2 个答案:

答案 0 :(得分:5)

是的,你读错了。

反向迭代器不需要存储指向元素开始之前的指针。

为了说明,取一个包含2个元素的数组:

int a[2];

这些是前向迭代器:

a+0 a+1 a+2 // The last one is not dereferenceable

反向迭代器将以相反的顺序用相同的值表示:

a+2 a+1 a+0 // The last one cannot be dereferenced

因此,虽然解除引用正常的迭代器非常简单,但反向迭代器取消引用稍微复杂一些:pointer[-1](对于随机访问迭代器来说,其他更糟糕的是:{{1 }})。

请注意,使用forward-iterator比反向迭代器更常见,因此前者比后者更有可能为它们优化代码。然而,由于所有转换都是一个不错的优化编译器,但是没有碰到那个角落的通用代码很可能在任何一种类型下运行得更好。

答案 1 :(得分:4)

std::make_reverse_iterator(begin(vec))不可解除引用,与end(vec)无法解除引用的方式相同。它没有“指向”任何有效的对象,这没关系。