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.
Related
The book Object oriented programming in c++ by Robert Lafore says,
A static local variable has the visibility of an automatic local
variable (that is, inside the function containing it). However, its
lifetime is the same as that of a global variable, except that it
doesn’t come into existence until the first call to the function
containing it. Thereafter it remains in existence for the life of the
program
What does coming into existence after first call of function mean? The storage for static local is allocated at the time program is loaded in the memory.
The storage is allocated before main is entered, but (for example) if the static object has a ctor with side effects, those side effects might be delayed until just before the first time the function is called.
Note, however, that this is not necessarily the case. Constant initialization is only required to happen before that block is entered (not necessarily just as execution "crosses" that definition). Likewise, implementations are allowed to initialize other block-scope static variables earlier than required under some circumstances (if you want to get into the gory details of the circumstances, you can look at [basic.start.init] and [stmt.dcl], but it basically comes down to: as long as it doesn't affect the value with which it's initialized. For example, if you had something like:
int i;
std::cin >> i;
{
static int x = i;
...the implementation wouldn't be able to initialize x until the block was entered, because the value with which it was being initialized wouldn't be known until them. On the other hand, if you had:
{
static int i = 0;
...the implementation could carry out the initialization as early as it wished (and most would/will basically carry out such an initialization at compile time, so it won't involve executing any instructions at run-time at all). Even for less trivial cases, however, earlier initialization is allowed when logically possible (e.g., the value isn't coming from previous execution).
In C++ storage duration of an object (when raw memory gets allocated for it) and lifetime of an object are two separate concepts. The author was apparently referring to the latter one when he was talking about object's "coming into existence".
In general case it is not enough to allocate storage for an object to make it "come into existence". Lifetime of an object with non-trivial initialization begins once its initialization is complete. For example, an object of a class with a non-trivial constructor does not officially "live" until its constructor has completed execution.
Initialization of a static local object is performed when the control passes over the declaration for the very first time. Before that the object does not officially exist, even if the memory for it is already allocated.
Note that the author is not painstakingly precise in his description. It is not sufficient to just call the function containing the declaration. The control has to pass through the declaration of the object for it to begin its lifetime. If the function contains branching, this does not necessarily happen during the very first call to the function.
For object with trivial initialization (like int objects), there's no difference between storage duration and lifetime. For such objects allocating memory is all that needs to be done. But in general case allocating memory alone is not sufficient.
It means that the static variable inside a function doesn't get initialized (by the constructor or the assignment operator) until the first call for that function.
As soon as the function, which contains a static local variable, is called the static local variable is initialized.
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.
I have C++ code which declares static-lifetime variables which are initialized by function calls. The called function constructs a vector instance and calls its push_back method. Is the code risking doom via the C++ static initialization order fiasco? If not, why not?
Supplementary information:
What's the "static initialization order fiasco"?
It's explained in C++ FAQ 10.14
Why would I think use of vector could trigger the fiasco?
It's possible that the vector constructor makes use of the value of another static-lifetime variable initialized dynamically. If so, then there is nothing to ensure that vector's variable is initialized before I use vector in my code. Initializing result (see code below) could end up calling the vector constructor before vector's dependencies are fully initialized, leading to access to uninitialized memory.
What does this code look like anyway?
struct QueryEngine {
QueryEngine(const char *query, string *result_ptr)
: query(query), result_ptr(result_ptr) { }
static void AddQuery(const char *query, string *result_ptr) {
if (pending == NULL)
pending = new vector<QueryEngine>;
pending->push_back(QueryEngine(query, result_ptr));
}
const char *query;
string *result_ptr;
static vector<QueryEngine> *pending;
};
vector<QueryEngine> *QueryEngine::pending = NULL;
void Register(const char *query, string *result_ptr) {
QueryEngine::AddQuery(query, result_ptr);
}
string result = Register("query", &result);
Fortunately, static objects are zero-initialised even before any other initialisation is performed (even before the "true" initialisation of the same objects), so you know that the NULL will be set on that pointer long before Register is first invoked.1
Now, in terms of operating on your vector, it appears that (technically) you could run into such a problem:
[C++11: 17.6.5.9/3]: A C++ standard library function shall not directly or indirectly modify objects (1.10) accessible by threads other than the current thread unless the objects are accessed directly or indirectly via the function’s non-const arguments, including this.
[C++11: 17.6.5.9/4]: [Note: This means, for example, that implementations can’t use a static object for internal purposes without synchronization because it could cause a data race even in programs that do not explicitly share objects between threads. —end note]
Notice that, although synchronisation is being required in this note, that's been mentioned within a passage that ultimately acknowledges that static implementation details are otherwise allowed.
That being said, it seems like the standard should further state that user code should avoid operating on standard containers during static initialisation, if the intent were that the semantics of such code could not be guaranteed; I'd consider this a defect in the standard, either way. It should be clearer.
1 And it is a NULL pointer, whatever the bit-wise representation of that may be, rather than a blot to all-zero-bits.
vector doesn't depend on anything preventing its use in dynamic initialisation of statics. The only issue with your code is a lack of thread safety - no particular reason to think you should care about that, unless you have statics whose construction spawns threads....
Initializing result (see code below) could end up calling the vector constructor before that class is fully initialized, leading to access to uninitialized memory.
No... initialising result calls AddQuery which checks if (pending == NULL) - the initialisation to NULL will certainly have been done before any dynamic initialisation, per 3.6.2/2:
Constant initialization is performed:
...
— 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
So even if the result assignment is in a different translation unit it's safe. See 3.6.2/2:
Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization. Static initialization shall be performed before any dynamic initialization takes place.
When will a fundamental C++ type, such as int or float, have an unknown initial value?
How does the type of memory allocation factor in, if at all? What about the declaration? What if it's a member of a class/struct/union? Is C++11 different from C++03 or C++98?
I have my suspicions, but no idea if my knowledge is complete (or correct, for that matter)
Any POD data (including all fundamental types) will have an unknown value when both:
it doesn't have static memory allocation (it's instead created on the stack or with new)
it isn't initialized, including empty initialization and/or constructor initialization lists
Global/static variables, of all types, are set to zero as part of the startup process before main is called. Constructors are called for types that have constructors before main 1.
Anything not initialized in the constructor is also unknown.
Edit: to clarify, std::string is a good example of "constructor not initializing everything" - if you have a local std::string str;, then str will have a defined "empty string" content, but the content of the actual buffer, or indeed what the buffer points at may not be set to anything meaningful at all - as the implementation may determine based on the length [or some other way] whether there is a buffer available or not once we start using the string to store stuff].
Edit2: As the comment explains, you can also have "hybrid" cases, where parts of a structure is being initialized, e.g. a struct that contains some elements of "plain data" and some elements that have constructors. The ones that have constructors will have their constructor called. The plain data will not be initialized.
1 It may well be that the code running constructors is part of, or called from inside the "main" function - but if that is the case, it will be "before any of your code in main is started".
From "Working Draft C++, 2012-11-02"
3.6.2 Initialization of non-local variables [basic.start.init]
2 Variables with static storage duration (3.7.1) or thread storage duration (3.7.2) shall be zero-initialized (8.5)
before any other initialization takes place.
Variables with static storage are at least zero initialized.
3.7.3 Automatic storage duration [basic.stc.auto]
2 [ Note: These variables are initialized and destroyed as described in 6.7. — end note ]
6.7 says nothing about how automatic variables are initialized.
3.7.4 Dynamic storage duration [basic.stc.dynamic]
...
3.7.4.1 Allocation functions [basic.stc.dynamic.allocation]
... There are no constraints on the contents of the allocated storage on return from the
allocation function. The order, contiguity, and initial value of storage allocated by successive calls to an
allocation function are unspecified.
8.5 Initializers [dcl.init]
7 To default-initialize an object of type T means:
— if T is a (possibly cv-qualified) class type (Clause 9), the default constructor for T is called (and the
initialization is ill-formed if T has no accessible default constructor);
— if T is an array type, each element is default-initialized;
— otherwise, no initialization is performed.
If you provide an explicit initializer, any variable will have a known value.
If you don't provide an explicit initializer for a POD type, it depends on the storage class. Static or thread variables will be zero initialized, whereas automatic or dynamically allocated variables are not.
If you have a compound type, the same rules apply. If you have don't have an explicit initializer, through a (default) constructor or otherwise, the initial value of fundamental types depends on the storage class.
Finally, memory allocated through malloc will be uninitialized, whereas calloc memory will be zero initialized.
I have a single instance of a simple POD
a.hpp
class A {
struct Zzz {
A* m_aPtr;
int m_val;
}
static Zzz s_zzz;
};
a.cpp
A::Zzz A::s_zzz;
I expect that both s_zzz.m_aPtr and s_zzz.m_val will be initialized to zeros before any other static initialization in any other compilation unit and it is guaranteed by the language itself. Am I right about it?
Usually I provide default constructors for the structs. Say
A::Zzz::Zzz() :
m_aPtr(0),
m_val(0)
{
}
Will it create initialization order problem or introduce compiler dependencies?
At least in C++0x, you can rely on all zero-initialization being performed before any other initialization code runs.
From the C++0x FCD, section [basic.start.init]
Variables with static storage duration
(3.7.1) or thread storage duration
(3.7.2) shall be zero-initialized
(8.5) before any other initialization
takes place.
If you're considering using this variable from other initialization code, then an explicit constructor would be a big mistake, as it would run sometime mixed in with other initialization code, and overwrite whatever changes have already been made by other initializers.
I expect that both s_zzz.m_aPtr and
s_zzz.m_val will be initialized to
zeros before any other static
initialization in any other
compilation unit and it is guaranteed
by the language itself.
It will be zero-initialized, since it's a static lifetime variable at namespace scope.
That zero-initialization happens before any dynamic initialization (an example of dynamic initializatin is when you some explicit initialization, or the class has a constructor).
The order of zero-initialization between different translation units is not defined, but there's not any way to detect it or rely on it since it happens before anything else, so it doesn't matter.
Re your point 2, it's rather unclear what you're asking about.
But for your static lifetime object, the effect is just that it's first zero-initialized, and then during dynamic initialization your constructor is used to zero it again (although the compiler might be smart enough to optimize away that redundant extra initialization).
Cheers & hth.,
ERRATA: Ben Voigt has provided a convincing example that the last paragraph above is wrong. So please disregard. The presence of the constructor means that the object can be dynamically initialized at some point before, between or after operations that change it, causing rather unpredictable results…
There are no guarantees about initialization order of statics between compilation units (see http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14).
If it has a constructor, it will no longer be a POD, unfortunately.
Static data is always initialised to zero.
No it shouldn't introduce any initialisation problems.
When the application is loaded into memory, the static area is initialised to zero. This is before any code starts to execute.