Running this on my setup:
vector<int> myvector;
for (int i=1; i<=5; i++) myvector.insert(myvector.end(),i);
vector<int>::iterator it;
for ( it=myvector.begin() ; it < myvector.end()+2; it++ )
cout << " " << *it;
Yields:
1 2 3 4 5 0 0
I would have thought that trying to dereference an out-of-range iterator would have resulted in a segfault. But it seems to yield an empty or default-initialized object of the type contained in the vector.
Is this well defined behaviour? And where does this property come from, from the iterator or from the vector? Does the iterator in some sense catch the out-of-range-exception and instead return an empty object?
I tried finding this in the C++11 reference, but it feels like it’s a bit over my head.
No, it gives undefined behaviour. The language does not require iterator accesses to be checked, as that would require a run-time check. C++ usually tries to avoid unnecessary run-time overhead, leaving the programmer to perform whatever checks are necessary.
Most modern platforms use paged virtual memory, providing memory protection with a granularity of a few kilobytes. This means that there is often accessible memory after an allocated block (such as the one managed by
std::vector), in which case out-of-range accesses will simply stomp on that memory.It may be possible to enable run-time iterator checks in your C++ library; alternatively, tools such as valgrind or efence can help to debug various memory errors, including out-of-range accesses.