The initialization of non-local non-inline variables: does it take place strictly before the `main()` function call?

北战南征 提交于 2019-12-08 03:34:42

问题


Is the order in which digits will be printed in the following simple program implementation-defined?

#include <iostream>


struct Foo
{
    Foo()
    {
        std::cout << "1" << std::endl;
    }
};

Foo foo;


int main()
{
    std::cout << "2" << std::endl;
}

Some wordings from the standard (Dynamic initialization of non-local variables [basic.start.dynamic]/4):

It is implementation-defined whether the dynamic initialization of a non-local non-inline variable with static storage duration is sequenced before the first statement of main or is deferred. If it is deferred, it strongly happens before any non-initialization odr-use of any non-inline function or non-inline variable defined in the same translation unit as the variable to be initialized.*

...

*) A non-local variable with static storage duration having initialization with side effects is initialized in this case, even if it is not itself odr-used ([basic.def.odr], [basic.stc.static]).

And the main() function is not odr-used.


回答1:


The permitted outputs are 1/2, 2, and 2/1.

If initialization of the variable foo is not deferred, then it is sequenced before the start of main, so 1 is printed before 2.

If the initialization is deferred, then the requirement is that initialization of foo must happen before any (other) odr-use of foo. It does not say that no initialization must happen if there is no odr-use. The output 2/1 would definitely be very odd for this example (and the output 2 the only one used in practice by implementations which defer initialization), but I don't see anything in the standard that strictly rules it out.

I believe the reason for the wording in the standard is that it allows implementations to use one guard for deferring the initialization of all such variables in a translation unit. If we amend your example like this:

…
Foo foo;

struct Bar {
  Bar() { std::cout << "3\n"; }
  void Use() {}
} bar;


int main()
{
    std::cout << "2" << std::endl;
    bar.Use();
}

With a single guard and deferred initialization, foo would be initialized along with bar, even though there is no odr-use (besides initialization) of foo in the program. In this case, it is also required for consistency because the example uses ordered initialization, so the initialization of foo must be sequenced before bar, so the only permitted outputs are 1/3/2 (no deferred initialization) and 2/1/3 (deferred initialization). But if we used a different construct to obtain unordered initialization, an implementation might also produce 2/3/1 (again, with no non-initialization odr-use of foo).



来源:https://stackoverflow.com/questions/54167232/the-initialization-of-non-local-non-inline-variables-does-it-take-place-strictl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!