From the Standard 6.7/4:
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.
It's not clear if the zero-initialization's being performed during the program-startup or during the control first executes the block?
I will report a longer snippet. That's your secction
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 a block-scope entity with static storage
duration, if applicable, is performed before its block is first
entered.
That's the follow up, and I understand that this means it can do both. That's the meaning I give to this section (the continuation of the same paragraph)
An implementation is permitted to perform early
initialization of other block-scope variables with static or thread
storage duration under the same conditions that an implementation is
permitted to statically initialize a variable with static or thread
storage duration in namespace scope (3.6.2).
All we can do now is wait a native english speaker to confirm/confute my legalese decryption...
Related
From Scott Meyers Effective C++:
if you never call a function emulating a non-local static object, you
never incur the cost of constructing and destructing the object,
something that can’t be said for true non-local static objects.
The function:
FileSystem& tfs()
{
static FileSystem fs;
return fs;
}
But the Standard said:
Constant initialization (3.6.2) of a block-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 or thread
storage duration under the same conditions that an implementation is
permitted to statically initialize a variable with static or thread
storage duration in namespace scope (3.6.2).
That means that we can't say for sure if the fs variable is or is not initialized even if we don't call to the function tfs(). Because implementation is permitted to perform early initialization as for variables with static storage duration.
Who was right or what did I miss?
Constant initialization describes initialization that can be determined at compile-time.
Only in C++11 and later can a type with a non-trivial constructor be considered:
if the constructor is constexpr
In "Effective C++", Meyers describes the class in your question literally as:
class FileSystem {...};
This would imply that given the C++ Standard being correct, "Effective C++" can also remain correct even after C++11 as long as the supplied constructor for FileSystem is not constexpr.
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.
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.
I heard that after some version of gcc using simply something like:
static A* a = new A();
return a;
Is thread-safe for a singleton and one wouldn't need something adapted from say http://locklessinc.com/articles/singleton_pattern/ anymore...
Does anyone have a specific reference or link to where I can read about this?
Section 6.7 of draft standard (n3337.pdf), point 4:
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 a
block-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 or
thread storage duration under the same conditions that an implementation is permitted to statically initialize
a 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.
GCC follows the cross-vendor Itanium C++ ABI. The relevant sections covering thread-safe initialization of function-local statics are 2.8 Initialization guard variables and 3.3.2 One-time Construction API, which says:
An implementation that does not anticipate supporting multi-threading may simply check the first byte (i.e., the byte with lowest address) of that guard variable, initializing if and only if its value is zero, and then setting it to a non-zero value.
However, an implementation intending to support automatically thread-safe, one-time initialization (as opposed to requiring explicit user control for thread safety) may make use of the following API functions:
...
There were some bugs in the early GCC implementation of that API, I think they are all fixed and it works correctly from GCC version 4.3 (possibly earlier, I don't recall and can't find a reference right now.)
However, Singleton is a bad, bad pattern, do not use it!