Almost everything related to c++ iostreams has this code smell of OOP pushed too far:
- Usage of runtime virtual dispatch with virtual calls when it was not necessary. Causing a negative unavoidable impact on performance.
- Heavy usage of function overloading with the "<<" operator. Leading to pages long compilation errors when an overload fails.
- Hidden states everywhere with the usage of state formatters and globals in the background.
- Unnecessary complexity with std::locale which is almost entirely useless for proper internationalisation.
- Bloat. Any statically compiled binary will inherit around ~100k of binary fat bloat when using iostream
- Useless encapsulation with error reports done as abstracted bit flags. Which is absolutely horrendous when dealing with file I/O: It hides away the underlying error with no proper way to access it.
- Deep class hierarchy making the entire thing looks like spaghetti.
- Useless abstraction with stringstream that hides the underlying buffer away, making it close to unusable on embedded safety critical systems where memory allocations are forbidden.
All of that made <iostreams> aged pretty badly, and for good reasons.
Fortunately there is an incoming way out of that with work of Victor Zverovich on std::format and libfmt [1].