Static global vs local variables.
Or how to deal with static initialization order fiasco... Or not...
A few days ago I was trying to avoid unnecessary object initializations, which should be a story on its own, and decided to use a constant static global to make sure all clients reuse the same instance. When I submitted my changes for review, our CI kindly ran a battery of linters and came back with a warning reminding me about Static Initialization Order Fiasco and suggested using a static local variable instead. Let’s use a simple example for illustrative purposes:
and it’s suggested replacement
I have to agree that I like the suggested pattern - it’s self-contained and makes initialization order explicit. What not to like about it? Very few things in life come for free. A few years ago I worked on improving cold startup of our iOS apps so I knew what compilers and linkers do to initialize static globals - their constructor is added to a global array of functions that are called by dynamic linker before calling main. Unfortunately, it hurts startup performance, but it means no overhead for the clients
Surely static local variables are initialized differently, but how? Well, let’s take a look
Ouch, looks like we end up having to perform an initialization check on each invocation and also use guards to avoid races. This branch should be easy to predict, since it would be false only once and true for all other invocations, so it’s unlikely to result in a significant performance overhead, but in case it ends up in a hot section, don’t forget to consider this overhead.