How are static local POD constants initialized? Little or not?

POD means a primitive data type without constructor and destructor.

I am curious how compilers handle lazy initialization of static local POD variables. What is the meaning of lazy initialization if the function is designed to work inside hard loops in multi-threaded applications? These are the possible options. Which one is better?

void foo_1() { static const int v[4] = {1, 2, 3, 4}; } void foo_2() { const int v[4] = {1, 2, 3, 4}; } 

How about this? No lazy initialization, but slightly awkward syntax?

 struct Bar { static const int v[4]; void foo_3() { // do something } }; const int My::v[4] = {1, 2, 3, 4}; 
+4
source share
6 answers

When a static variable is initialized with persistent data, all the compilers I am familiar with will initialize the values ​​at compile time so that there is no additional time required to execute.

If the variable is not static, it must be assigned for each function call, and the values ​​must be copied to it. I believe it is possible that the compiler can optimize this in static if it is a const variable, except that a constant can be dropped.

+4
source

In foo_1() , v initialized around the start of main() . In foo_2() , v is created and initialized each time foo_2() called. Use foo_1() to eliminate this extra cost.

In the second example, Bar::v also initialized until approximately main() .

+2
source

Performance is harder than just distribution. For example, you can cause the extra cache line to be in the cache with a static variable, because it does not touch the other local memory that you are using, and increase the pressure in the cache, skipping the cache, etc. Compared to this value, I would say that the incredibly tiny overhead of redistributing the array in the stack would be very trivial every time. Not only that, but any compiler is great for optimizing such things, while it can't do anything about static variables.

In any case, I would suggest that the difference in performance between them is minimal - even for a closed loop.

Finally, you can also use foo_2 () - the compiler perfectly has the right to make such a variable as static in it. Since it was originally defined as const, const_casting, const const is an undefined behavior, regardless of whether it is static. However, it cannot select a static constant, not a static one, since you could depend on the ability to return its address, for example.

+2
source

An easy way to find out how variables are initialized is to print a list of function assembler languages ​​with static and local variables.

Not all compilers initialize variables in the same method. Here is a common practice: Before the main() global variables are initialized by copying the value section into the variables. Many compilers put constants in an area so that data can be assigned using simple move or copy commands.

Local variables (variables with a local scope) can be initialized by entering a local scope and before the first statement in the scope is executed. It depends on many factors, one of which is a const variable.

Constants can be placed directly in the executable code, or they can be a pointer to a value in ROM or copied to memory or registered. This is determined by the compiler for maximum performance or code size, depending on the compiler settings.

+1
source

On the technical side, foo_1 and foo_3 needed to initialize their arrays before any functions are called, including class constructors. This guarantee is essentially as good as a lack of lead time. And in practice, most implementations do not require any runtime to initialize them.

This guarantee applies only to objects of type POD with static storage duration that are initialized using "persistent expressions". Some more contrasting examples:

 void foo_4() { static const int v[4] = { firstv(), 2, 3, 4 }; } namespace { // anonymous const int foo_5_data[4] = { firstv(), 2, 3, 4 }; } void foo_5() { const int (&v)[4] = foo_5_data; } 

Data for foo_4 initialized the first time foo_4 called. (Check your compiler documentation to see if it is thread safe!)

The data for foo_5 initialized some time before main() , but may be after some other dynamic initializations.

But none of this answers questions about performance, and I have no right to comment on it. @DeadMG's answer seems to be helpful.

+1
source

You have static initialization in all of these cases, all of your static variables will be initialized by loading the data segment into memory. The constant in foo_2 can be initialized if the compiler considers this possible. If you had dynamic initialization, then the initialization of variables in the namespace area may be delayed until their first use. Similarly, the dynamic initialization of local static variables in the scope of a function can be performed during the first pass through a function or earlier. In addition, the compiler can statically initialize these variables if it is capable of doing so. I do not remember the exact wording from the Standard.

+1
source

Source: https://habr.com/ru/post/1333093/


All Articles