Re: Validity of references returned from iterators
On Wednesday, 31 July 2013 06:07:09 UTC+1, Christopher Head wrote:
I was in the process of writing an STL-style iterator class. I grabbed
N3337 (as I don't have access to the actual standard) and looked at the
requirements for the various iterator types. I couldn't seem to find,
anywhere, the rules describing over what period of time pointers and
references returned from iterators are valid. That is to say, given
this code:
template<typename Titer> void f(Titer iter) {
T &elt = *iter;
// Do something with iter
elt.do_something();
}
what are the things I am allowed to do in the commented line and expect
elt to still be a useful reference to the same element it initially
pointed to?
For the standard STL containers, of course, the answer is easy: I'm
allowed to do pretty much anything with iter, because elt points to an
object in the underlying container which has nothing to do with the
iterator.
I did find this sentence in [iterator.requirements.general]:
=93Destruction of an iterator may invalidate pointers and references
previously obtained from that iterator.=94
That's all well and good, but I couldn't find *any* other cases which
were documented as allowed to invalidate said pointers and references.
If Titer were istream_iterator, for example, then doing =93++iter=94 woul=
d
be bad: using elt is, if I understand correctly, undefined behaviour in
that case. Now, I know that istream_iterator is an input iterator and I
know that input iterators specify that after invoking ++r, any copies
of the old value of r are no longer required to be dereferenceable. OK,
but that doesn't actually say anything about the validity of elt, which
was initialized back when iter *was* dereferenceable=97and iter, the
iterator from which elt was initialized, certainly hasn't been
destroyed, so the sentence I pasted from general requirements doesn't
apply!
My question is thus: what are the rules, and where in the standard are
they defined?
The simple answer is that there aren't any rules; each iterator
defines its own rules. And they often involve things other than
the iterator: insert or erase on a container can invalidate
iterators, references or pointers into the container, for
example. Destruction or modification of the iterator can
invalidate the reference (but only for InputIterator, if
I recall correctly). And so on. If you design your own
iterator, you set the rules. If you write a template function
which takes an iterator as a template argument, you specify the
minimum rules that iterator has to adhere to, and so on.
--
James