In example code, I often see code such as *it++
for output iterators. The expression *it++
makes a copy of it
, increments it
, and then returns the copy which is finally dereferenced. As I understand it, making a copy of an output iterator invalidates the source. But then the increment of it
that is performed after creating the copy would be illegal, right? Is my understanding of output iterators flawed?
views:
204answers:
5Isn't an iterator just a pointer? Incrementing, then dereferencing it just moves on to the next element.
Output iterators just don't work like normal iterators and their interface is specified so that they can be used in pointer-like expressions (*it++ = x
) with useful results.
Typically, operator*()
, operator++()
and operator++(int)
all return *this
as a reference and output iterators have a magic operator=
which performs the expected output operation. Because you can't read from an output iterator, the fact that operator*()
etc., don't work as for other iterators doesn't matter.
The standard requires that *r++ = t
work for output iterators (24.1.2). If it doesn't work, it's not an output iterator by the standard's definition.
It is up to the iterator implementation to make sure such statements work correctly under the hood.
The reason that you shouldn't keep multiple copies of an output iterator is that it has single pass semantics. The iterator can only be dereferenced once at each value (i.e. it has to be incremented between each dereference operation). Once an iterator is dereferenced, a copy of it cannot be.
This is why *r++ = t
works. A copy is made of the orignal iterator, the original iterator is dereferenced and the copy is incremented. The original iterator will never be used again, and the copy no longer references the same value.
Looking at your comment, it seems that most of the confusion arises from the SGI documentation, which I'd say is a bit misleading on this point.
Copying an output iterator does not invalidate the copied iterator. The real limitation is pretty simple: you should only dereference a given value of output iterator once. Having two copies at a time, however, is fine as long as you only dereference once of them while they have the same value. In a case like there where you're dereferencing one, then throwing away its value, and incrementing the other but only dereferencing it after the increment has happened, it's all perfectly fine.
The expression *it++
does not (have to) make a copy of it, does not increment it, etc.
This expression is valid only for convenience, as it follows the usual semantics. Only operator=
does the actual job. For example, in g++ implementation of ostream_iterator
, operator*
, operator++
and operator++(int)
do only one thing: return *this
(in other words, nothing!). We could write for example:
it = 1;
it = 2;
*it = 3;
++it = 4;
Instead of: *it++ = 1; *it++ = 2; *it++ = 3; *it++ = 4;