arch detail

arch detail

Wednesday, November 17, 2010

C++ Iterators: Interesting bug

I've often heard it said that C++ lends itself to surprising and subtle bugs. I recently encountered an interesting (and simple) example myself.

I have a class foo which holds an iterable implemented with the STL (say, in this case, a std::set of ints); say this iterable is called myBar. So we give foo public member functions getBar() and setBar().

class foo {
public:
const std::set getBar() { return myBar; } const;
void setBar(std::set newIntSet) { myBar = newIntSet; };

private:
std::set myBar;
};


At one point, I wanted to iterate over myFoo.myBar, so I used the following:

std::set::const_iterator barIter;
for (barIter = myFoo.getBar().begin();
barIter != myFoo.getBar().end();
barIter++) {
Do work on barIter
}


This periodically produced some really horrible behavior. Do you see why?

It's because we call getBar() once when we start the "for" loop (barIter = myFoo.getBar().begin()) and get one copy of myFoo.myBar. At every successive iteration of the loop, we get another copy of myFoo.myBar, when checking for the termination condition: barIter != myFoo.getBar().end().

Amazingly, this didn't manifest right away with a seg fault or other conspicuous error. This is probably because for all STL iterators that I know of, .end() evaluates to NULL, so we could iterate barIter until it pointed at a 0 in memory, at which point the iteration would stop.

Surprisingly, on my program barIter would usually point at memory which held a copy of myBar. It wasn't until we had a non-trivial program that I found this bug; in fact, this broken program would often pass unit tests!

Overall, this was a boneheaded mistake on my part. Once I put on my C programmer cap and thought about what the compiler was doing, it was easy to see why this was wrong.

Overall, this experience strengthens my belief that one should never do C++ without doing a lot of low-level C programming first, and that C++ classes can hurt as much as they can help.

No comments: