Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is "vector iterator + offset out of range" assertion useful at all?

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.

like image 560
Paul Jurczak Avatar asked Dec 26 '22 06:12

Paul Jurczak


2 Answers

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 with iTo += 5 you terminate your loop as iFrom != 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:

for (auto iFrom = v.cbegin(), iTo = iFrom; iFrom != v.cend(); iFrom = iTo)
{
    iTo += 5;
    cout << *max_element(iFrom, iTo) << '\n';
}
like image 101
Tony Delroy Avatar answered Mar 16 '23 01:03

Tony Delroy


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.

like image 43
sfjac Avatar answered Mar 16 '23 00:03

sfjac