Iterator Invalidation

These days there’s this well-seated OOP craze in the CS world. OOP is far from new, but in the relatively recent past (10-20 years?) it has gone from “Oh, that” to rock stardom. Everyone loves to “abstract away from implementation details”. The idea sounds great on paper, but sometimes it’ll bite ya in the ass.

The standard C++ library has a bunch of built in data containers to make your life easier. The most common one is probably the vector. Vectors store their contents in a contiguous block of memory. They can be iterated through very efficiently and make your cache much happier. Vectors also come with a bunch of operations. Some of my favorites are the push_back and pop functions.

How do these functions work internally? Ahh, that’s just a tiny implementation detail! Or IS it?

Let’s say we have the following program:

#include <iostream>
#include <vector>

int main(int argc, char* argv[])
{
	std::vector<char> vowels;

	std::cout << "Setting up our vector of vicious vowels!" << std::endl;
	vowels.push_back('a');
	vowels.push_back('e');
	vowels.push_back('i');
	vowels.push_back('o');

	char* favorite_vowel = &vowels[2]; // Our favorite vowel is i!

	std::cout << "Favorite vowel: " << *favorite_vowel << std::endl;

	std::cout << "WAIT!  We forgot to include 'u'.  Let's stick it on the end of the array!" << std::endl;

	vowels.push_back('u');

	std::cout << "Okay, but my favorite vowel is still: " << *favorite_vowel << std::endl;

	std::cin.get();

	return 0;
}

Your output may be different than mine, but when I compile and run this program, I get the following:

Setting up our vector of vicious vowels!
Favorite vowel: i
WAIT!  We forgot to include 'u'.  Let's stick it on the end of the array!
Okay, but my favorite vowel is still: 3

Wait a second… my favorite vowel isn’t 3. In fact, 3 isn’t a vowel–it isn’t even a letter! And what’s more, there is no 3 in our entire program. So where the hell is our 3 coming from?
Continue Reading »