Reverse iterator returns garbage when optimized

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.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)