8 ms·
Data initialization in C++
- apaprocki 13y agoFile-level static non-POD instances are a big no-no. If you really (really) need a global static, move it into function scope in a function which returns the static (singleton pattern). (Additional tricks can be used to ensure it is only initialized once in a thread-safe manner.) e.g. https://github.com/bloomberg/bsl/blob/master/groups/bsl/bslma/bslma_mallocfreeallocator.cpp#L40 https://github.com/bloomberg/bsl/blob/master/groups/bsl/bslm...
- nanidin 13y agoStatic 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.
- mpyne 13y agoAre you saying this to violently agree with the OP? He covers exactly this in his section "What is the problem with global objects with constructor?", where he even points out the function-scope macro that can be used to help alleviate the problem.
- apaprocki 13y agoYes, but I feel it is not stated prominently/strongly enough. Having them can easily lead to a lot of other problems down the line, so to me it's not so much a recommendation as an order -- don't do this!
- kruhft 13y agoThis is my first exposure to constexpr and it looks very interesting. According to this article it's a second C++ metaprogramming language: http://cpptruths.blogspot.ca/2011/07/want-speed-use-constexpr-meta.html http://cpptruths.blogspot.ca/2011/07/want-speed-use-constexp.... The more I learn about C++11 the more I like it. There's some really amazing new features that I've only seen in Lisps, plus there's full static typing, which is the one thing I miss from Lisps.
- deleted 13y ago[deleted]
- pubby 13y agoThe more I use C++11 the less I like it. constexpr has many problems: - Its syntax is that of C++s, but limited to a single statement and so is about as expressive as a block of wood. Templates are much closer to functional languages and so are naturally more expressive. Seriously, use templates instead! - It's inefficient. If you want to do heavy computations then you're better off writing a program to generate code. If you want efficient run-time performance then good luck optimizing a single statement. - It's specification is full of quirks and pitfalls. Quite simply, constexpr does not follow the path of least surprise. Plus, I hear it was a nightmare for the compiler writers.
- malkia 13y agoI feel the same with every new coming C++ feature. From the recent I like auto, and I only wish anonymous functions call syntax was a bit easier. Here is a good usage of constexpr - http://www.macieira.org/blog/2011/07/initialising-an-array-with-cx0x-using-constexpr-and-variadic-templates/ http://www.macieira.org/blog/2011/07/initialising-an-array-w...
- kruhft 13y agoAfter reading up on Lisp macro programming (PG's on OnLisp and others) you will see that it is always advised to use only purely functional code when doing metaprogramming. In Common Lisp and all the others Lisps I've seen, this is not strictly enforced by the language and only advised. The code should be purely functional because you don't know when and how many times it can be called by the compiler leading to some grand mysteries when something does not go as expected during compilation due to unintended state. The constexpr design is taking this to heart and enforcing that the code to be purely functional. I don't see this as a disadvantage but take it that designers of C++ are forcing best practices for the features they are adding. Best practices are generally not the most convenient, but by doing it this way, they're giving you less 'rope to shoot yourself in the foot'. Lisp was more of a research language woring as a testbed of features that are now moving into mainstream languages now that there is some experience with how to use them in the least damaging way. Purely functional programming is not as 'easy' to write because almost everyone learns imperative first, which is the most natural way to code (do this, then do this, then do this,...). Using functional code requires you put the control that you would normally put into code into the data. It's a different way of thinking and is not natural in the way that imperative programming is. And regarding that implementing constexpr wsa a 'nightmare for compiler writers', it should be! Strong abstractions are difficult to design and implement, but once they are complete everyone benefits. Compilers are the one things that should take on the hard features since everyone uses them. Thanks for your experiences with constexpr and I'll form my own opinions of it after some practial use and maybe i'll find it just as lacking as you do in the end :). I'll stand by my statement that C++11 is heading in the right direction, even though it may have some warts and tradeoffs that it can't be avoided, like anything that matures. It will be interesting to see what C++ goes in the next 10 or more years.