Friday, February 08, 2008

C++: Little teaser about std::set

This does not build. Can you guess why? Without testing it?
std::set< int > numbers;

for (int i = 0; i < 10; i++)
numbers.insert(i);

for (std::set< int >::iterator iter = numbers.begin();
iter != numbers.end(); iter++) {
int& i = *iter;
i++;
}
Update (23:40): John gave a correct answer in the comments.

7 comments:

Lluis said...

Julio! You should know... you are missing the 'include' and the 'main' XD

C++ is sometimes too weird...

John said...

The problem comes with i++ in your second for loop.

Since i is an int& and you assigned it *iter, it is the same as using *iter. *iter is read only, so that is why the increment breaks the build.

Just a guess :)

Julio M. Merino Vidal said...

John: Exactly, that's why it fails.

Now the real question is: why is *iter read-only if the code is using an iterator and not a const_iterator?

lrrr said...

Well, this is surprise for me as well, but seems that iterator type doesn't have to be mutable.

I don't have the ISO standard by hand, but SGI STL documentation says that for Container, X::iterator must be an 'input iterator', which is not required to be mutable.

John said...

The reason why *iter is read only is because the elements in the set are also keys. If you were able to modify *iter, then you run the risk of having two or more of the same key.

Also, the elements are sorted (I think), so modifying *iter would mean the set would have to sort itself after every iteration.

Julio M. Merino Vidal said...

John: Bingo!

This piece of code bothered me this morning for a while until I came to this same conclusion. I assumed it had to work because it surely does when you use, for example, a vector instead of a set, but when you think about it you realize it cannot work :-)

John said...

Yeah, I ran into the same problem while working on a school project. It definitely caught me off guard.

This is fun, you should do it more often :)