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 »

C++
General

Comments (0)

Permalink

Pointer Decay in C++

“Arrays are really just pointers”.

This is one of the biggest “gotchas” out there. It’s one that, at the end of the day, really isn’t even that big of a deal. You could live happily for the rest of your life convinced that arrays and pointers are the exact same thing (though I wouldn’t recommend it). But arrays aren’t pointers. They decay into pointers. Plus you can’t change where they point to, but that really isn’t the point here..

Before I go on, I want to pick this very obvious spot to point out that everything I’m about to explain was pulled almost entirely from this thread on gamedev, including most of the program below (with other, clearer versions in the thread). Reading through that post will probably benefit you much more than reading through this one, especially the parts on the extra indirection after a function call towards the end, which won’t be mentioned here.

Anyway, take the following code:

#include <iostream>
#include <string>

static const size_t ARRAY_SIZE=5;

void display_array_info(int size, const std::string &title)
{
	std::cout << title << std::endl;
	std::cout << "Array size: " << size << std::endl;
}

template <typename T, size_t U>
void reference(const T (&some_array)[U])
{
	display_array_info(sizeof(some_array), "By Reference:");
}
template <typename T, size_t U>
void value(const T some_array[])
{
	display_array_info(sizeof(some_array), "By \"Value\":");
}

template <typename U>
void pointer(const U* const some_array)
{
	display_array_info(sizeof(some_array), "By Pointer:");
}

int main(int argc, char *argv[]) {
	int integer_array[ARRAY_SIZE] = { 2, 4, 6, 8, 10 };

	std::cout << "From Main:" << std::endl;
	std::cout << "Array size: " << sizeof(integer_array) << std::endl;

	pointer<int>(integer_array);
	value<int, ARRAY_SIZE>(integer_array);
	reference<int, ARRAY_SIZE>(integer_array);

	std::cin.get();

	return 0;
}

Which, for me, will output:

From Main:
Array size: 20
By Pointer:
Array size: 4
By "Value":
Array size: 4
By Reference:
Array size: 20

(the array takes up 20 bytes in total…)

So what exactly is going on here?
Continue Reading »

C++
General

Comments (0)

Permalink