简体   繁体   中英

Why using `std::reverse_iterator` doesn't invoke UB?

I was working with std::reverse_iterator today and was thinking about how it works with values created by calling begin on a container. According to cppreference , if I have reverse_iterator r constructed from iterator i , the following has to hold &*r == &*(i-1) .

However, this would mean that if I write this

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

iter now points to piece of memory that is placed before begin(vec) , which is out of bounds. By strict interpretation of C++ standard, this invokes UB.

(There is specific provision for pointer/iterator to element 1-past-the-end of the array, but as far as I know, none for pointer/iterator to element 1-ahead-of-the-start of an array.)

So, am I reading the link wrong, or is there a specific provision in the standard for this case, or is it that when using reverse_iterator , the whole array is taken as reversed and as such, pointer to ahead of the array is actually pointer past the end?

Yes, you are reading it wrong.

There is no need for reverse-iterators to store pointers pointing before the start of an element.

To illustrate, take an array of 2 elements:

int a[2];

These are the forward-iterators:

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

The reverse-iterators would be represented with these exact same values, in reverse order:

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

So, while dereferencing a normal iterator is really straightforward, a reverse-iterator-dereference is slightly more complicated: pointer[-1] (That's for random-access iterators, the others are worse: It copy = pointer; --copy; return *copy; ).

Be aware that using forward-iterators is far more common than reverse-iterators, thus the former are more likely to have optimized code for them than the latter. Generic code which does not hit that corner is about as likely to run better with either type though, due to all the transformations a decent optimizing compiler does.

std::make_reverse_iterator(begin(vec)) is not dereferenceable, in the same way that end(vec) is not dereferenceable. It doesn't "point" to any valid object, and that's OK.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM