My opinion of C++ iostreams has improved substantially over time, particularly after I started to actually extend them by implementing my own stream classes. I began to appreciate the extensibility and overall design, despite the ridiculously poor member function names like xsputn
or whatever. Regardless, I think I/O streams are a massive improvement over C stdio.h, which has no type safety and is riddled with major security flaws.
I think the main problem with IO streams is that they conflate two related but somewhat orthogonal concepts: textual formatting and serialization. On the one hand, IO streams are designed to produce a human-readable, formatted textual representation of an object, and on the other hand, to serialize an object into a portable format. Sometimes these two goals are one and the same, but other times this results in some seriously annoying incongruities. For example:
std::stringstream ss;
std::string output_string = "Hello world";
ss << output_string;
...
std::string input_string;
ss >> input_string;
std::cout << input_string;
Here, what we get as input is not what we originally outputted to the stream. This is because the <<
operator outputs the entire string, whereas the >>
operator will only read from the stream until it encounters a whitespace character, since there's no length information stored in the stream. So even though we output a string object containing "hello world", we're only going to input a string object containing "hello". So while the stream has served its purpose as a formatting facility, it has failed to properly serialize and then unserialize the object.
You might say that IO streams weren't designed to be serialization facilities, but if that's the case, what are input streams really for? Besides, in practice I/O streams are often used to serialize objects, because there are no other standard serialization facilities. Consider boost::date_time
or boost::numeric::ublas::matrix
, where if you output a matrix object with the <<
operator, you'll get the same exact matrix when you input it using the >>
operator. But in order to accomplish this, the Boost designers had to store column count and row count information as textual data in the output, which compromises the actual human-readable display. Again, an awkward combination of textual formatting facilities and serialization.
Note how most other languages separate these two facilities. In Java, for example, formatting is accomplished through the toString()
method, while serialization is accomplished through the Serializable
interface.
In my opinion, the best solution would have been to introduce byte based streams, alongside the standard character based streams. These streams would operate on binary data, with no concern for human-readable formatting/display. They could be used solely as serialization/deserialization facilities, to translate C++ objects into portable byte sequences.