开发者

Dynamic initialization phase of static variables

开发者 https://www.devze.com 2023-03-13 15:42 出处:网络
The standard specifically state开发者_Python百科s that dynamic initialization of static duration variables (namespace scope and class static members) does not have to occur before main is executed:

The standard specifically state开发者_Python百科s that dynamic initialization of static duration variables (namespace scope and class static members) does not have to occur before main is executed: "It is implementation-defined whether or not the dynamic initialization (8.5, 9.4, 12.1, 12.6.1) of an object of namespace scope is done before the first statement of main." IS 3.6.2(3) Is it not how dynamic initialization is [always?] implemented? What better/easier way to guarantee that the objects are initialized before use?


The answer to your question is in the next sentence (in 3.6.2 of ISO/IEC 14882-2003) after the one you've quoted.

It is implementation-defined whether or not the dynamic initialization (8.5, 9.4, 12.1, 12.6.1) of an object of namespace scope is done before the first statement of main. If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first use of any function or object defined in the same translation unit as the object to be initialized.

Obviously to make sure that some variable X is initialized you just have to use in function main (directly or indirectly) any function or variable defined in the same translation unit as the variable X (e.g. if you directly or indirectly use X in function main then you may be sure it is already initialized).

EDIT:

If in addition to the assurance that the variable you use is already initialized (it always is - as guaranteed by the standard text quoted above) you also want to know why standard contains the provision that initialization may be delayed after main execution start.

I mean if the question is also: Why not just demand that all initialization is performed before main starts?

Well it is definitely not about dynamically linked libraries - no problem to initialize all their objects before starting main. Also it is not about dynamically loaded libraries (LoadLibrary/dlopen) - they are not within a realm of C++ standard obviously (they are not subject to One Definition Rule for example and in general they may even be not C++).

In theory this provision allows lazy initialization to avoid unnecessary runtime overhead - e.g. unless you actually use some function or object from a specific translation unit (C++ source file) you don't have to do its runtime initialization. But it is unlikely that any implementation actually do lazy initialization in runtime - multi-threading synchronization is challenging for this kind of initialization and is itself a runtime overhead.

BUT what every single implementation actually do is linking only those modules (translation units) that are actually used. So even if you link with some static library that contain some dynamically initialized object (maybe with side effect - like file creation or user interaction) but don't use anything from the same translation unit - implementation is not obliged to run initialization of this object at all. So this provision allows avoiding inclusion of any unused translation units in final executable - even if they are formally part of the program.


I believe the intention here is to allow dynamic load libraries.

Static variables defined in the libraries are not guaranteed to be initialized before main, but must happen before anything in the specific library is used.


This isn't a direct answer, but it might be interesting for comparison's sake to go over how a similar language (Ada) handles this same situation.

In Ada packages (the rough equivalent to namespaces) can have data with initializations which effectively have the same lifetime as the program, much like Cish statics (for simplicity we will ignore generic packages, which like templates may be created in lower scopes). The process of doing these initializations is called "elaboration".

Ada guarantees that all packages will be elaborated at the start of the main routine. However, it is quite possible to create "elaboration" code that will not work if another package has not yet been elaborated yet. In general, the compiler gets to pick the elaboration order. So writing code that will not work unless the compiler happens to pick the order you need is considered a "Bounded Error".

Obviously this isn't ideal, as it is often desirable to use non-builtin data types in other packages, and sometimes this will include some with initializations that will need to be elaborated. So Ada provides some pragmas to allow you to ask the compiler to elaborate some or all of your dependencies before the current package.

It isn't perfect. It is quite possible to write code for which there really is no valid elaboration order. If you do this (or don't get the pragma's right and the compiler can't figure it out either), you get a Program_Error exception raised during elaboration. Some debuggers have trouble stepping through elaboration code, so these errors can be a major PITA to track down. Nonetheless, I really miss this facility in C++. It is the difference between being able to use complex objects in "static" declarations if you are careful, and having to avoid them altogether.


The dynamic initialization of static duration variables (namespace scope and class static members) ALWAYS occurs before main is executed.
The order in which these static duration variables get initialized is not defined.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号