Yet another broken zero cost abstraction promise.
Or why it's good not to include what you don't use.
Even though my performance work is usually focused on runtime, sometimes my build time frustration gets to a point when there is no other choice but to confront it. Fortunately, there is a build-bench online service that makes these kinds of investigations a lot easier.
Interestingly, its default comparison is between compilation of C’s puts and C++’s iostream hello world. Even though I’m somewhat familiar with hidden corners of iostream, the difference still surprised me - 37X!
Ouch! It would be reasonable to suspect that it has something to do with complex operator lookup machinery or some metaprogramming shenanigans that iostream does. But what if we comment out puts and cout, so that we have empty mains with unused includes? Turns out it’s still 33X slower!
To understand what’s taking so much time, I’d usually use a compiler profiler or use GCC’s -ftime-report to get a breakdown. But before I get a chance to do this, I’ve noticed an output in the compiler explorer - in case of unused cstdio the assembly looks as expected
but in the case of iostream we get
which suggests that we are also running ios_base initialization pre main. Since we don’t use anything from the iostream header, according to zero cost abstraction principle, we should not pay anything, apart from build time overhead for processing this unused header.
The moral of the story? Even if you don’t care about your build time, you have more reasons to invest in tooling to rid of unused includes.
That's a nice reminder. Thanks. I always say that C++ hello world is one of the more complicated hello world programs to explain. std::cout is .. global object, << are overloaded and std::endl is ... a function that will \n + flush. Why? since << has an overload that takes a function!
I once heard that some companies will penalize developers if they #include <iostream>. Urban myth? perhaps! :)