In VC++2008 there is a serious difference in initialization of static local variable and static local object. Static local variable is initialized before main() and its definition statement within the function is skipped. Static local object is initialized by 0 value before main() and its definition statement within the function is executed only once . Constructor is started and object is initialized by appropiate value. All that can be seen in Debug mode. Does this solution correspond to the existing C++ Standard?
From http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf :
Every object of static storage
duration shall be zero-initialized at
program startup before any other
initialization takes place. [ Note: in
some cases, additional initialization
is done later. —end note ]
Related
In C++ I know static and global objects are constructed before the main function. But as you know, in C, there is no such kind initialization procedure before main.
For example, in my code:
int global_int1 = 5;
int global_int2;
static int static_int1 = 4;
static int static_int2;
When are these four variables initialized?
Where values for initialization like 5 and 4 are stored during compilation? How to manage them when initialization?
EDIT:
Clarification of 2nd question.
In my code I use 5 to initialize global_int1, so how can the compiler assign 5 to global_int? For example, maybe the compiler first store the 5 value at somewhere (i.e. a table), and get this value when initialization begins.
As to "How to manage them when initialization?", it is realy vague and I myself does not how to interpret yet. Sometimes, it is not easy to explain a question. Overlook it since I have not mastered the question fully yet.
By static and global objects, I presume you mean objects with
static lifetime defined at namespace scope. When such objects
are defined with local scope, the rules are slightly different.
Formally, C++ initializes such variables in three phases:
1. Zero initialization
2. Static initialization
3. Dynamic initialization
The language also distinguishes between variables which require
dynamic initialization, and those which require static
initialization: all static objects (objects with static
lifetime) are first zero initialized, then objects with static
initialization are initialized, and then dynamic initialization
occurs.
As a simple first approximation, dynamic initialization means
that some code must be executed; typically, static
initialization doesn't. Thus:
extern int f();
int g1 = 42; // static initialization
int g2 = f(); // dynamic initialization
Another approximization would be that static initialization is
what C supports (for variables with static lifetime), dynamic
everything else.
How the compiler does this depends, of course, on the
initialization, but on disk based systems, where the executable
is loaded into memory from disk, the values for static
initialization are part of the image on disk, and loaded
directly by the system from the disk. On a classical Unix
system, global variables would be divided into three "segments":
text:
The code, loaded into a write protected area. Static
variables with `const` types would also be placed here.
data:
Static variables with static initializers.
bss:
Static variables with no-initializer (C and C++) or with dynamic
initialization (C++). The executable contains no image for this
segment, and the system simply sets it all to `0` before
starting your code.
I suspect that a lot of modern systems still use something
similar.
EDIT:
One additional remark: the above refers to C++03. For existing
programs, C++11 probably doesn't change anything, but it does
add constexpr (which means that some user defined functions
can still be static initialization) and thread local variables,
which opens up a whole new can of worms.
Preface: The word "static" has a vast number of different meanings in C++. Don't get confused.
All your objects have static storage duration. That is because they are neither automatic nor dynamic. (Nor thread-local, though thread-local is a bit like static.)
In C++, Static objects are initialized in two phases: static initialization, and dynamic initialization.
Dynamic initialization requires actual code to execute, so this happens for objects that start with a constructor call, or where the initializer is an expression that can only be evaluated at runtime.
Static initialization is when the initializer is known statically and no constructor needs to run. (Static initialization is either zero-initialization or constant-initialization.) This is the case for your int variables with constant initializer, and you are guaranteed that those are indeed initialized in the static phase.
(Static-storage variables with dynamic initialization are also zero-initialzed statically before anything else happens.)
The crucial point is that the static initialization phase doens't "run" at all. The data is there right from the start. That means that there is no "ordering" or any other such dynamic property that concerns static initialization. The initial values are hard-coded into your program binary, if you will.
When are these four variables initialized?
As you say, this happens before program startup, i.e. before main begins. C does not specify it further; in C++, these happen during the static initialisation phase before objects with more complicated constructors or initialisers.
Where values for initialization like 5 and 4 are stored during compilation?
Typically, the non-zero values are stored in a data segment in the program file, while the zero values are in a bss segment which just reserves enough memory for the variables. When the program starts, the data segment is loaded into memory and the bss segment is set to zero. (Of course, the language standard doesn't specify this, so a compiler could do something else, like generate code to initialise each variables before running main).
Paraphrased from the standard:
All variables which do not have dynamic storage duration, do not have thread local storage duration, and are not local, have static storage duration. In other words, all globals have static storage duration.
Static objects with dynamic initialization are not necessarily created before the first statement in the main function. It is implementation defined as to whether these objects are created before the first statement in main, or before the first use of any function or variable defined in the same translation unit as the static variable to be initialized.
So, in your code, global_int1 and static_int1 are definitely initialized before the first statement in main because they are statically initialized. However, global_int2 and static_int2 are dynamically initialized, so their initialization is implementation defined according to the rule I mentioned above.
As for your second point, I'm not sure I understand what you mean. Could you clarify?
Lets say foo is called once in a program, and
void foo()
{
if(sometimes_false())
{
static int xx = func_with_sideeffect();
}
}
the condition wasn't met, is the side-effect
1. Allowed to have happened
2. Mandated to have happened (I'm guessing not if my compiler is conforming)
3. Mandated to not have happened
The non-constant initialization of all variable with local scope and static storage duration is from the point it is encountered till the end of the program. So, if the variable is not encountered because of a condition, it would not be initialized and the side effect won't happen.
The following quote from the standard supports the answer (particularly the part in bold)
6.7 Declaration statement [stmt.dcl]
The zero-initialization (8.5) of all block-scope variables with static
storage duration (3.7.1) or thread storage duration (3.7.2) is
performed before any other initialization takes place. Constant
initialization (3.6.2) of ablock-scope entity with static storage
duration, if applicable, is performed before its block is first
entered.An implementation is permitted to perform early initialization
of other block-scope variables with static orthread storage duration
under the same conditions that an implementation is permitted to
statically initializea variable with static or thread storage duration
in namespace scope (3.6.2). Otherwise such a variable is initialized
the first time control passes through its declaration; such a
variable is considered initialized upon the completion of its
initialization. If the initialization exits by throwing an exception,
the initialization is not complete, so it will be tried again the next
time control enters the declaration. If control enters the declaration
concurrently while the variable is being initialized, the concurrent
execution shall wait for completion of the initialization.88 If control
re-enters the declaration recursively while the variable is
being initialized, the behavior is undefined.
The answer is 3 but you need to think about threading.
The static int xx will be initialised by the first thread encountering that variable, and C++11 will block all other threads at that point until func_with_sideeffect() returns and the result has been assigned to xx. (That's not the case with older standards: a mutex would have been required).
It's more difficult to predict the destruction of xx if it was an instance of an object with a non-trivial destructor.
Overarching question is: how can a programmer make sure that his non-local static variables are initialized via static initialization and not via dynamic initialization?
As zero-initialization is done always then one should look at the constant initialization.
3.6.2.2 A constant initializer for an object o is an expression that is a constant expression, except that it may also invoke constexpr
constructors for o and its subobjects even if those objects are of
non-literal class types [ Note: such a class may have a non-trivial
destructor —end note ]. Constant initialization is performed:
— if each full-expression (including implicit conversions) that
appears in the initializer of a reference with static or thread
storage duration is a constant expression (5.19) and the reference is
bound to an lvalue designating an object with static storage duration
or to a temporary (see 12.2);
— if an object with static or thread storage duration is initialized
by a constructor call, and if the initialization full-expression is a
constant initializer for the object;
— if an object with static or thread storage duration is not
initialized by a constructor call and if either the object is
value-initialized or every full-expression that appears in its
initializer is a constant expression.
I omitted the reference as it is not important in my case. How I understand the standard is that there are 3 cases:
ctor
no-ctor and value initialization
no-ctor and constant expression
Let's say I have a following class:
struct X {
bool flag = false;
// = {} will break VS2013 CTP so in that case use the
// regular ctor, which sadly still can't be declared constexpr
std::aligned_storage<sizeof(int), alignof(int)>::type storage = {};
};
As far as I can say this class is perfectly valid for constant initialization (each element can be constantly initialized). Is this true?
Does this class require a constexpr constructor?
Is constant initialization guaranteed for C++11 as well as C++98?
Side question: When will the static initialization done in case of so/dll? During the load time, or it might be delayed even further?
It would be good to know the purpose behind this question. And also whether your concern is allocation or specifically initialization.
However, the type of initialization shouldn't matter because the required space is allocated at compile time. Depending on how you define the variable, it will end up either in .bss or .data section.
Initialization, as you know, is only to ensure a specific content in the memory before it is first used. If you do not define a constructor that allocates dynamic memory then there won't be any dynamic allocation (if that is your concern).
For simple constructors, I believe the compiler will generate inline code and use the same to initialize the object at compile time (I am not sure what the standard talks about the same but it is possible that it is tool chain dependent.) With complex constructors, non-local static objects will be initialized when the image is loaded in memory and local static objects will be initialized when the stack frame is loaded. In any cases you should find the object in a known state before first use.
Side question: When will the static initialization done in case of
so/dll? During the load time, or it might be delayed even further?
On Windows, static initialization occurs before before DllMain() is invoked with the DLL loader lock acquired. This severely limits what you can do in the constructors for your static objects. You can't load any other DLLs (LoadLibrary) or call any other function that MIGHT cause a DLL to be loaded, which pretty much rules out anything beyond simple initialization and functions exported by Kernel32.
See the last few paragraphs of the DllMain (MSDN) docs for details.
In this topic they said that zero initialization is not static initialization.
Can anyone explain why?
3.6.2/2 said:
Together, zero-initialization and constant initialization are called
static initialization;
It is definition of Static initialization, means that zero-initialization is static initialization and constant-initialization is static Initialization
This answer assumes that you know what static storage duration means.
In C++03 this is specified as (3.6.2):
Objects with static storage duration (3.7.1) shall be zero-initialized
(8.5) before any other initialization takes place. Zero-initialization
and initialization with a constant expression are collectively called
static initialization; all other initialization is dynamic
initialization.
In practice, a program has different memory segments where it stores variables with static storage duration:
One segment is usually called .bss, where all static storage variables that are initialized to zero are stored.
Another segment is usually called .data, where all static storage variables that are explicitly initialized to a value are stored.
And further, there is a segment called .rodata where all const variables are stored.
(The reason why these are two different segments is mainly program startup performance, you can read more about that here.)
Zero initialization applies to all variables stored in .bss and constant initialization applies to all variables stored in .data. (And perhaps constant initialization applies to .rodata as well, depending on whether your system is RAM-based or if it has true ROM).
Collectively, all of this is called static initialization, since it applies to objects with static storage duration.
You forgot to notify the word "Together", very important in this sentence.
Zero-initialization + constant initialization = static initialization. Is that clearer ?
It's just vocabulary. There are clearly three phases of
initialization (for variables with static lifetime): zero
initialization, initialization using constant expressions, and
dynamic initialization. I find it convenient when talking about
this to use the term static initialization for the second step
(because it does take place statically, without the execution of
any user written code), even if the standard uses a somewhat
different terminology. In the end, it comes down to the same
thing:
int a;
int b = 42;
int c = someFunction();
Formally, all three variables will be zero-initialized. Then
b will be initialized with the constant expression 42; in
all likelyhood, it will never actually be zero-initialized,
because there's no way your code can ever see it before the
constant initialization. Finally, c will be initialized by
calling someFunction().
This order is true regardless of the order of the definitions,
and is guaranteed by the standard.
The post you link to says that zero-initialization is not static initialization. This is correct.
That is very different from zero-initialization is not a static initialization! This is not correct.
When and how are const variables initialized in C/C++? I am curious about particular types:
1) const static member of a class
2) function const local variable
3) const global variable
I mean of course application run time not source code way of initializing them.
1) const static member of a class
If it's a simple type initialised with a constant expression, then it's initialised during the static initialisation phase, before any user code is run.
Otherwise, if it's a class type with a non-trivial constructor, or has a non-constant initialiser, then it's initialised during the dynamic initialisation phase. This will happen before any function that's defined in the same translation unit is called; but there are potential deathtraps:
It might not happen before other static variables are initialised; you'll get evil bugs if their constructors access it.
It might not happen before main begins, if it's defined in a different unit.
It might not happen at all, if you never call any function in the same unit.
2) function const local variable
If it's static, then it's initialised the first time the program reaches its definition. If it's automatic, it's initialised every time the program reaches it, and destroyed when it goes out of scope.
3) const global variable
Same as the first. Both have static storage duration, and so are initialised and destroyed according to the same rules.
Notes:
Since you're asking about two different languages: in C, there's no such thing as "dynamic initialisation", and all non-local static variables are initialised before any user code runs.
Being const has no effect on when or how a variable is initialised.
Storage duration tells you what rules apply for when the variable in a program is allocated and deallocated. To answer your question is to specify storage duration for each case that you mentioned.
1) const static member of a class : static storage duration,
simple type - static initialisation,
class with non-trivial constructor - dynamic
initialisation
2) function const local variable : automatic storage duration ( but static
duration if it is static const),
automatic variable is initialized each time
the code is run,
static variable is initialized the first
time code is run,
3) const global variable : static storage duration
simple type - static initialisation,
class with non-trivial constructor - dynamic
initialisation
Explanation of storage durations:
automatic storage duration
The variable is allocated at the beginning of the enclosing code block
and deallocated on end. All non-global variables have this storage
duration, except those declared static, extern or thread_local.
static storage duration
The variable is allocated when the program begins and deallocated when
the program ends. Only one instance of the variable exists. All global
variables have this storage duration, plus those declared with static
or extern.
thread storage duration
The variable is allocated when the thread begins and deallocated when
the thread ends. Each thread has its own instance of the variable.
Only variables declared thread_local have this storage duration.
thread_local can appear together with static or extern to adjust
linkage. (since C++11)
dynamic storage duration
The variable is allocated and deallocated per request by using dynamic
memory allocation functions.