This perfectly good program fails in debug mode in Visual Studio 2013:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void main()
{
vector<int> v = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3};
for (auto iFrom = v.cbegin(), iTo = iFrom+5; iFrom != v.cend(); iFrom = iTo, iTo += 5)
cout << *max_element(iFrom, iTo) << '\n';
}
with vector iterator + offset out of range
assertion failure. It fails because iTo > v.cend()
, which is harmless here. What is the point of debugger testing the value of iterator, which is not being dereferenced?
BTW, I know that I can rewrite the loop above as:
for (auto i = v.cbegin(); i != v.cend(); i += 5)
cout << *max_element(i, i+5) << '\n';
but I was trying to make a simple example out of a piece of more complex real-life code, where calculating the new iterator value is computationally expensive.
I also realize that one can change _ITERATOR_DEBUG_LEVEL
value to affect this behavior, but it creates problems with binary versions of some libraries, which are built with default debug settings.
It's not harmless... it's undefined behaviour to attempt to move the iterator past
end()
, which you do on your third and final iteration. The fact that immediately after doing so withiTo += 5
you terminate your loop asiFrom != v.cend()
without dereferencing the iterator is not relevant.If efficiency is really necessary and you're prepared the bet the bank on the number of elements being a multiple of 5:
Not completely sure what the question is here, but the "point" is that VS is trying to aid in removing dangerous code. Yes, in principle a pointer could point anywhere if you didn't dereference it, but iterators are a higher level abstraction and have the ability to detect whether dereference would be valid and thus raise runtime errors. VS has done this with
vector<T>::iterator
at least since VS 2007.max_element() takes two iterators and goes over the entire range between them. If you think about it, the range isn't really valid if either of the iterators are invalid. Both SGI and Microsoft mention this as a prerequisite in their respective documentation:
SGI:
MSDN:
If I were in your situation, I'd just add a check to see if iTo was still valid as the first step in my loop. If it's not, set it to the last position in v.