At the top of some file in my program, outside all functions, I have these variables:
namespace {
int foo = foo_func();
}
int bar = bar_func();
As you know, foo is a variable local only to that file, but bar is accessible to every file.
...but question: When are the functions foo_func() and bar_func() actually run? Does this happen before main() runs, or possibly sometime later (say just before those values are actually needed)?
The language specification states that the initializing functions will be executed before any function from that translation unit is called or any object defined in that translation unit is accessed. So, in general case it really depends on how your definitions are spread across translation units.
The initialization is carried out in top-to-bottom order, so, given your order of definitions, bar_func should see already initialized foo, but foo_func should see "uninitialized" (i.e. zero-initialized) bar.
Note, that if your main resides in another translation unit, it means that the initialization does not have to happen before main(). Yet, if you attempt to access foo or bar from main (or from anywhere else), that should guarantee that the initialization process is triggered for the entire translation unit that defined these variables.
Also, if your initializers are constant expressions (constexpr functions), then the whole initialization can be performed statically, which typically means that the variables will begin their lifetimes in already initialized (compile-time initialized) states.
Initializing with the return value from a non-constexpr function is dynamic initialization. Order of dynamic initialization is defined as follows (leaving out some details I think are irrelevant to your question):
§3.6.2/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 ordered initialization defined within a single translation unit shall be initialized in the order of their definitions in the translation unit. If a program starts a thread (30.3), the subsequent initialization of a variable is unsequenced with respect to the initialization of a variable defined in a different translation unit. Otherwise, the initialization of a variable is indeterminately sequenced with respect to the initialization of a variable defined in a different translation unit.
§3.6.2/3:
An implementation is permitted to perform the initialization of a non-local variable with static storage duration as a static initialization even if such initialization is not required to be done statically, provided that [Jerry's summary: it produces the same result as if it had been done dynamically.]
§3.6.2/4:
It is implementation-defined whether the dynamic initialization of a non-local variable with static storage duration 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 odr-use (3.2) of any function or variable defined in the same translation unit as the variable to be initialized
Related
Given this class in the header file:
class ClassA
{
public:
ClassA(){};
}
Then in file.cpp
#include file.h
ClassA* GlobalPointerToClassAType = new ClassA();
a. Is it allowed, and is it good practice to use the keyword 'new' to allocate memory for an object in the heap(?) in lines of file-scope?
b. If it is allowed, then when exactly does the constructor ClassA() is actually called?
c. How does it differ if I wrote instead this line:
ClassA GlobalInstanceOfClassAType = ClassA();
in terms of the time of calling the constructor, in terms of memory efficiency, and in terms of good practice?
a. Is it allowed, and is it good practice to use the keyword 'new' to allocate memory for an object in the heap(?) in lines of file-scope?
It is allowed. Whether is it good practice to use new here is opinion based. And i predict that most people will answer no.
b. If it is allowed, then when exactly does the constructor ClassA() is actually called?
Let's start from some concepts.
In C++, all objects in a program have one of the following storage durations:
automatic
static
thread (since C++11)
dynamic
And if you check the cppreference, it claim:
static storage duration. The storage for the object is allocated when the program begins and deallocated when the program ends. Only one instance of the object exists. All objects declared at namespace scope (including global namespace) have this storage duration, plus those declared with static or extern. See Non-local variables and Static local variables for details on initialization of objects with this storage duration.
So, GlobalPointerToClassAType has static storage duration, it fit the statement that "All objects declared at namespace scope (including global namespace) have this storage duration...".
And if you get deeper into the link of the above section, you will find:
All non-local variables with static storage duration are initialized as part of program startup, before the execution of the main function begins (unless deferred, see below). All non-local variables with thread-local storage duration are initialized as part of thread launch, sequenced-before the execution of the thread function begins. For both of these classes of variables, initialization occurs in two distinct stages:
There's more detail in the same site, you can go deeper if you want to get more, but for this question, let's only focus on the initialization time. According to the reference, The constructor ClassA() might be called before the execution of the main function begins (unless deferred).
What is "deferred"? The answer is in the below sections:
It is implementation-defined whether dynamic initialization happens-before the first statement of the main function (for statics) or the initial function of the thread (for thread-locals), or deferred to happen after.
If the initialization of a non-inline variable (since C++17) is deferred to happen after the first statement of main/thread function, it happens before the first odr-use of any variable with static/thread storage duration defined in the same translation unit as the variable to be initialized. If no variable or function is odr-used from a given translation unit, the non-local variables defined in that translation unit may never be initialized (this models the behavior of an on-demand dynamic library). However, as long as anything from a translation unit is odr-used, all non-local variables whose initialization or destruction has side effects will be initialized even if they are not used in the program.
Let's see a tiny example, from godbolt. I use clang, directly copy your code, except that the Class A and main are defined in the same translation unit. You can see clang generate some section like __cxx_global_var_init, where the class ctor is called.
If in a program I create a meyer's singleton and an object that uses this meyer's singleton in both its constructor and destructor, things are okay as long as the object that uses meyer's singleton is destroyed before the singleton itself (like when it is in a function scope).
Now if I make the same object global, I see seg fault. The reason is that the singleton gets destroyed before the global object.
Is this a compiler defined behaviour or standard defined behaviour? Is there any way we can modify this behaviour?
Any pointers will be appreciated.
What is the order of destruction for static objects and global objects?
The order of destruction of objects with static storage duration is the inverse of the order of their initialisation.
Is this a compiler defined behaviour or standard defined behaviour?
The inverse order of destruction is standard.
The order of initialisation of non-local static objects is the same as the order of declaration within a single translation unit. The order across translation units is unspecified. Local static objects are initialised when the execution first passes their declaration.
Is there any way we can modify this behaviour?
You can influence the order of initialisation of non-local static objects within a translation unit by reordering their declarations. You can influence the order of initialisation of local static objects by calling the function earlier or later. The order of destruction is indirectly influenced by changing the order of initialisation.
You cannot influence to order of initialisation of non-local objects with static storage duration between translation units, and you must not rely on that order.
In C++98/03, the construction of static objects(in files, in classes, in functions) has no specified sequence, one static object cannot assume it's constructed after or before another static object, seem to be decided by linker.
My question is, does C++ 11/14 specify any rules for the construction sequences of static objects and global objects?
The rules have not changed. However all global/static objects are constructed in the order they appear in the translation unit. It is just the order of initialization of multiple translation units that is unspecified.
Do note that function local static objects are constructed in a specified manner. They are constructed the first time the their declaration is reached and live until the end of the program. This behavior was changed in C++11 though as before C++11 that initialization was not thread safe where C++11 and above specifies that static initialization will be thread safe.
Yes: Global objects will be constructed in order within a compilation unit. Ando No: Nothing changed with C++11/14.
Question coming from another question I recently asked Referencing a possibly destroyed static object. Can a destructor for an instance of a class use a global primitive variable/constant? Is it guaranteed to hold its value till program termination (i.e. after the statics have been destroyed)?
I know that static object destruction across compilation units is not defined but I was wondering whether the same holds for primitive values.
For example
Something.cpp
extern bool global_boolean_value;
Something::~Something() {
assert(global_boolean_value);
}
With respect to initialization the standard lumps together everything with "static storage duration", which are the variables (including member variables) declared using the static keyword (variables with internal linkage) as well as "true globals" (variables with external linkage). The standard does not distinguish between plain old data types one one hand and structs or classes on the other.
Note after comments (all quotes from the 2012 standard):
3.7.1 Static storage duration [basic.stc.static]
1 All variables which do not have dynamic storage duration, do not have thread storage duration, and are not local have static storage duration. The storage for these entities shall last for the duration of the program (3.6.2, 3.6.3).
(Emphasis by me.) There is no distinction between PODs and non-PODs. Note that the paragraph defines the lifetime of the storage, not of the (typed, initialized) object. When the program (not main()!) starts, all static storage is readily allocated. And yes, the destructors of objects with static storage duration are part of the program. This makes it, as far as I can see, safe to access errno in a destructor.
As you say, there is no guarantee about the order of initialization of objects with static storage duration across different translation units; within one TU the initialization is performed in the definition order, and destruction is then done in the opposite order.
That is all there is to it (apart from workarounds, like putting your globals in an artificial class or returning static local variables from functions).
The answer to your example question then depends on the storage duration of the object for which the destructor is called. If the object has static storage duration and is in a different translation unit, you are out of luck. If it is automatically or dynamically allocated, or if it is defined in the same translation unit after the global variable you are fine.
The C++98 language standard states:
(My emphasis)
3.6.2 Initialization of nonlocal objects
£1
[...]
Zeroinitialization
and initialization with a constant expression are collectively
called static initialization; all other initialization is dynamic initialization.
[...]
£3
[...]
It is implementationdefined
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.
[...]
In my office, we have got two interpretations of the boldface passage...
My question is: There is a class has a whole bunch of static methods and dynamically initialized static data members. Can it (or can't it) happen that static methods in this class are called from another translation unit, before dynamic initialization has been completed?
Thanks!
[Edit:]
Perhaps this boils down to the reading of "it shall occur" as:
Shall have begun
Shall have been completed
Can it (or can't it) happen that static methods in this class are called from another translation unit, before dynamic initialization has been completed?
The bolded passage is pretty clear, isn't it?
Initialization of such data is guaranteed to happen before first use of any function or class defined in its translation unit. It doesn't matter where a function is called from. The guarantee is that initialization happens before the first use of any functions in the translation unit. Of course they may be called from another translation unit, but that doesn't make any difference. Before a function defined in this translation unit is entered, initialization must have been performed.
In other words, you're safe.
...
assuming single-threaded execution, that is. C++98 provides no guarantees in a multithreaded environment, so for a threaded application, the above guarantee typically just means that initialization will be performed by the first thread to use a function or class from this translation unit. And then you have a race condition while this initialization is being performed, where other threads might hit the partially-initialized data.