Looking at std::reverse_iterator‘s libstdc++ implementation reveals something interesting:
/**
* @return A reference to the value at @c --current
*
* This requires that @c --current is dereferenceable.
*
* @warning This implementation requires that for an iterator of the
* underlying iterator type, @c x, a reference obtained by
* @c *x remains valid after @c x has been modified or
* destroyed. This is a bug: http://gcc.gnu.org/PR51823
*/
_GLIBCXX17_CONSTEXPR reference
operator*() const
{
_Iterator __tmp = current;
return *--__tmp;
}
The @warning section tells us that a requirement of the underlying iterator type is that *x must remain valid even after the underlying iterator is modified/destroyed.
Looking at the mentioned bug link reveals more interesting information:
at some point between C++03 and C++11 the definition of reverse_iterator::operator* was changed to clarify this, making libstdc++’s implementation wrong. The standard now says:
[ Note: This operation must use an auxiliary member variable rather than a temporary variable to avoid returning a reference that persists beyond the lifetime of its associated iterator. (See 24.2.) —end note ]
comment by Jonathan Wakely (2012)
So it looks like a bug… but at the end of the topic:
The definition of reverse_iterator has been reverted to the C++03 version, which does not use an extra member, so “stashing iterators” can not be used with reverse_iterator.
comment by Jonathan Wakely (2014)
So it seems that using std::reverse_iterator with “stashing iterators” does indeed lead to UB.
Looking at the DR 2204: “reverse_iterator should not require a second copy of the base iterator” further clarifies the issue:
This note in 24.5.1.3.4 [reverse.iter.op.star]/2:
[ Note: This operation must use an auxiliary member variable rather than a temporary variable to avoid returning a reference that persists beyond the lifetime of its associated iterator. (See 24.2.) —end note ]
[my note: I think that the above note would fix your UB issue]
is incorrect because such iterator implementations are ruled out by 24.2.5 [forward.iterators]/6, where it says:
If a and b are both dereferenceable, then a == b if and only if *a and *b are bound to the same object.