4 ms·
Static init/de-init order were huge issues at my last job, working on embedded devices. When I say huge, I really mean issues that would seem to come and go ran
by nanidin 13y ago
Static init/de-init order were huge issues at my last job, working on embedded devices. When I say huge, I really mean issues that would seem to come and go randomly with builds, and in some cases brick devices until someone could JTAG it and get it up on a debugger to load a new boot block or determine the root cause. As the guy that got to do this, let me tell you that stepping through the ARM assembly of the runtime library made me feel like an uber hacker, but it wasn't exactly fun.
The nifty counter pattern[0] ended up being the most helpful for generating a static initialization and de-initialization order without conflicts. The tradeoffs are that it increases codesize and that it looks like magic to a lot of people. I don't remember the exact reason that wrapping everything in functions returning references didn't work - I think it was more to do with the de-init side of things, since the function wrappers guarantee the init order but not the de-init order.
[0] http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Nifty_Counter http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Nifty_Count...
- revelation 13y agoHow happy are you with C++ on embedded devices? If possible, could you specify what platform you are working on and what compiler support is like? I hear its popular among the Arduino crowd, but I've so far preferred C kernel style code for embedded.
- nanidin 13y agoI was working at Garmin - it was a mix of C and C++ on the devices. Most of Garmin's devices at the time ran Garmin's own proprietary OS, usually called GarminOS. The majority of the low level system code was written in C or ARM assembly, and the stuff in the application layer was more generally C++. There was definitely some of the C/C++ you read about too. I was happy with using C++ there - it didn't cause significant increases in code size, allowed STL container use, and was what I learned in undergrad, so it was easy. But it does present problems when you try to do everything the "C++ way" and get overzealous with OO design, then find out you now need to write a C wrapper so legacy code can call it. We used the official armcc compiler iirc, which we had binaries for linux/windows/etc. There were issues with building the code with gcc targeted at ARM and with clang I believe, it wasn't a priority to get it working but I'm sure it could have been done.
- huhtenberg 13y agoUhm... but why would you have globals with constructors in a code where de/initialization order matters?
- nanidin 13y agoMassive, legacy codebase, C wrappers around new C++ functionality... to be honest I don't remember the exact reason. It mostly had to do with concurrency primitives not being initialized when they needed to be due to a lack of a way to initialize a class instance the same way POD instances are initialized (aka int x = 0 in global scope.) You work with what you're given, sometimes! ;)
- pandaman 13y agoIt's not just globals with constructors and the order is not obvious. For example, few people (including yours truly) realize the whole complexity of the code like this: const float epsilon = 0.001f; const float one_sup = 1.f + epsilon; const float one_inf = 1.f - epsilon; I once spent a day trying to figure out what's going on when similar code suddenly (like after several years of constant use without any issues) broke.
- kstenerud 13y agoThere's an alternative nifty counter implementation that doesn't use as much memory. See near the bottom of http://www.petebecker.com/js/js199905.html http://www.petebecker.com/js/js199905.html
- nanidin 13y agoI read through the page, but nothing popped out to me as saving memory. Am I missing something obvious? They both look like they cost 1 static counter, plus sizeof(class instance with no member variables) per translation unit the header is included in.
- kstenerud 13y agoIn the alternate version, only one instance of the initializer object is maintained. In the standard version, there's one object instantiated and maintained for every file that included the header.