
David Abrahams <dave@boost-consulting.com> writes:
I'm getting ready to fix the issues we've discussed with postfix ++ (and by extension, --) in iterator_facade. Basically, the current implementation works for forward iterators but not for some input iterators:
{ self x = *this; ++*this; // <== here return x; }
The problem is that for many input iterators, all copies reference the same element. The marked line increments the iterator, which causes the current element of the sequence to be skipped, so
*a++
yields the /next/ element. To fix that, a++ needs to return a proxy type.
When considering this stuff, please look at n1640 and not C++98 or TC1, as n1640 contains fixes for outright bugs that survived to TC1 as well. In particular, *a++ was required to return an input iterator's value_type until recently.
If we don't know for certain that the iterator is a forward iterator and if *a returns something convertible to T const& (where T is the iterator's value type) it seems to me that we *must* assume that all copies of the iterator reference the same element, so the result of postfix ++ must be a proxy that contains a copy of *a.
The new iterator framework is intended to support iterators with bidirectional traversal that are not conforming forward iterators (e.g. their operator* may return by-value). If an iterator is incrementable it is also dereferenceable, but the same doesn't hold for decrementability, so I'm not sure what to do about the result of postfix --.
The best solution I can think of is that the actual decrement is delayed, and the iterator being decremented contains a flag that says "do an extra decrement before the next operation other than postfix decrement". That's a really bad solution, though: you can't really do a decrement in the destructor because it might throw, and such an iterator could easily have side-effects, so it'd be easy to get the iterator out-of-synch with expectations.
Actually there's no problem. The only iterators that need this sort of help with postfix increment are those that "consume" their inputs -- in other words, those that are not multipass iterators. All of the iterator concepts with bidirectional traversal capability are multipass. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com