Nifty/Schwarz counter, standard compliant?

后端 未结 2 1555
南笙
南笙 2020-12-15 06:31

I had a discussion this morning with a colleague about static variable initialization order. He mentioned the Nifty/Schwarz counter and I\'m (sort of) puzzled. I understan

相关标签:
2条回答
  • 2020-12-15 07:20

    I believe it's guaranteed to work. According to the standard ($3.6.2/1): "Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place."

    Since nifty_counter has static storage duration, it gets initialized before initializer is created, regardless of distribution across translation units.

    Edit: After rereading the section in question, and considering input from @Tadeusz Kopec's comment, I'm less certain about whether it's well defined as it stands right now, but it is quite trivial to ensure that it is well-defined: remove the initialization from the definition of nifty_counter, so it looks like:

    static int nifty_counter;
    

    Since it has static storage duration, it will be zero-initialized, even without specifying an intializer -- and removing the initializer removes any doubt about any other initialization taking place after the zero-initialization.

    0 讨论(0)
  • 2020-12-15 07:28

    I think missing from this example is how the construction of Stream is avoided, this often is non-portable. Besides the nifty counter the initialisers role is to construct something like:

    extern Stream in;
    

    Where one compilation unit has the memory associated with that object, whether there is some special constructor before the in-place new operator is used, or in the cases I've seen the memory is allocated in another way to avoid any conflicts. It seems to me that is there is a no-op constructor on this stream then the ordering of whether the initialiser is called first or the no-op constructor is not defined.

    To allocate an area of bytes is often non-portable for example for gnu iostream the space for cin is defined as:

    typedef char fake_istream[sizeof(istream)] __attribute__ ((aligned(__alignof__(istream))))
    ...
    fake_istream cin;
    

    llvm uses:

    _ALIGNAS_TYPE (__stdinbuf<char> ) static char __cin [sizeof(__stdinbuf <char>)];
    

    Both make certain assumption about the space needed for the object. Where the Schwarz Counter initialises with a placement new:

    new (&cin) istream(&buf)
    

    Practically this doesn't look that portable.

    I've noticed that some compilers like gnu, microsoft and AIX do have compiler extensions to influence static initialiser order:

    • For Gnu this is: Enable the init-priority with the -f flag and use __attribute__ ((init_priority (n))).
    • On windows with a microsoft compiler there is a #pragma (http://support.microsoft.com/kb/104248)
    0 讨论(0)
提交回复
热议问题