My work at Zemanta in the last two weeks included optimizing performance of some core software components. This mostly means moving stuff from Python to C++ which also means that I've been exposed to more C++ in the last week than in five years at the Faculty (where I tried to stay away from it as much as possible except for a few odd KDE hacks back when I still used it).
Anyway, IO streams always seemed awkward to me. But that's usually the case when you start using a language you're not fluent in. So I tried to go on with them and waited for the enlightenment when I would say "Oh! I don't know how I ever lived with the plain old stdio.h". Well, today I finally got it, but it was the other way around. I'm moments from making it a policy that all my C++ code will strictly use the plain old stdio.h for console and file I/O.
Why? Well, consider the following example. I want to make a string that will hold a hex representation of a 32 bit integer. It's going to be read by another program so the format must be pretty strict. Using the C++ way, you would do that like so:
stringstream g; g << "0x" << hex << setw(8) << setfill('0') << i << endl;
It's long and relatively unreadable. Add a couple more manipulators and you could easily have a statement that prints 10 characters span multiple lines. Compare this with C equivalent:
Ok, maybe I'm biased regarding readability. However compare what these two programs print out:
# C++ version 0x000b,eaf # C version 0x0000beaf
Why is there a comma in the middle? I just spent an hour debugging this earlier today. The cause? Well the comma is a thousands separator from the current locale which the stream library helpfully inserts in your string. Yes, a thousands separator that actually separates four thousand and ninety sixths. A solution? Adding another string manipulator that modifies the locale (a manipulator that just turns off the thousands separator doesn't actually exist). Just beautiful.
The fun doesn't stop there. I spent another hour today debugging some piece of code that opens a file. In the end it turned out that the open call was failing because I tried to open a file that was a couple of megabytes over the 2 GB limit and the program wasn't compiled with support for large files. I don't mind that, it was my mistake. However I do mind that it took me as long as it did to find the cause.
The fstream objects just silently fail when there is something wrong. The damn things don't even throw exceptions by default. Isn't that the C++ way of handling errors? Instead they set some hidden state you have to specially check and even then you can only get the message that something failed, not what specifically went wrong. Add to that the horrible mess that is STL documentation and you see why I only found out what was causing the program to crash when I dumped fstreams and rewrote the whole thing to use stdio.h functions.
So, in conclusion, C++ itself is pretty nice as a language (and blindingly fast compared to Python, which has the speed of a snail nailed to the table) but the standard infrastructure that comes with it causes more problems than it solves. Instead of using it and waiting to find out the bright sides of it, I'll use the old way I know from C and wait until someone else shares his enlightenment with me.