Search code examples
c++for-loopvectoriteratorindexoutofboundsexception

Vector iterator loop working with g++ but not VisualC++, why?


I have a program I wrote on my linux machine. It uses a std::vector<std::string> and I loop over it with a for loop like so

std::vector<std::string> words;
words.push_back("A");
words.push_back("B");
words.push_back("C");
// loop
for (auto it = words.end(); it >= words.begin(); it--)
{
    std::string word = *it; // invalid deref?
    // do things with word
    if (word == "B")
    {
        words.erase(it);
    }
    std::cout << word << std::endl;
}

int i = 0;
for (std::string word : words)
{
    std::cout << i++ << word << std::endl;
}

This runs as expected using g++ as the compiler, printing C, B and A. However when I run it with VisualStudio I get an invalid dereferencing exception.

I run through the vector backwards, because I want to delete items from it, and that messes with the iterator if you loop forwards.
I have a workaround using an integer and getting the items with std::vector<std::string>.at(int), but I am curious why this works with my linux machine but not windows?


Solution

  • As you correctly commented, there is an invalid dereferencing.

    std::string word = *it;
    

    Will be std::string word = *words.end() in the first iteration which results in undefined behaviour. So it's perfectly valid that it works on one system and throws an exception on another.

    The correct way to reverse-iterate a vector would be

    for(auto it = words.rbegin(); it != words.rend(); it++) {...}
    

    However, for deleting elements from a vector, the erase-remove-idiom might be more useful:

    words.erase(std::remove(words.begin(), words.end(), "B"), words.end());
    

    Or if you have a more complex condition, use a lambda:

    words.erase(std::remove_if(
       words.begin(), 
       words.end(), [](const std::string &name){return name == "B";}
    ), names.end());