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.
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++ 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?
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've been reading up on C++ on the Internet, and here's one thing that I haven't been quite able to find an answer to.
I know that static variables used within functions are akin to globals, and that subsequent invocations of that function will have the static variable retain its value between calls.
However, if the function is never called, does the static variable get allocated?
Thanks
If the function is never called, it is likely that your linker will deadstrip both the function and the static variable, preventing it from entering .rodata, .data, or .bss segments (or your executable file format's equivalents).
However, there are various reasons why a linker might not deadstrip (flags telling it not to, an inability to determine what depends on the symbol, etc).
It's worth checking your linker map file (sometimes just a text file!), or using objdump, nm, or dumpbin utilities on the final executable to see if the symbol or related symbols (such as static initializer code) survived.
The C++ Standard, section 6.7 says:
The zero-initialization (8.5) of all
local objects with static storage
duration (3.7.1) is performed before
any other initialization takes place.
A local object of POD type (3.9) with
static storage duration initialized
with constant-expressions is
initialized before its block is first
entered. An implementation is
permitted to per- form early
initialization of other local objects
with static storage duration under the
same conditions that an implementation
is permitted to statically initialize
an object with static storage duration
in namespace scope (3.6.2). Otherwise
such an object is initialized the
first time control passes through its
declaration; such an object is
considered initialized upon the
completion of its initialization.
Which indicates that local static objects are normally initialised the first time the control flow encounters them. However, they may well be allocated before this - the standard is somewhat reticent on what static storage actually is, except with reference to static object lifetimes.
Every object in C++ has two nested time-periods associated with it: storage duration and lifetime. Storage duration is the period for which the raw memory occupied by the object is allocated. Lifetime is the period between construction and destruction of an actual object in that memory. (For objects of POD-types construction-destruction either doesn't matter or not applicable, so their lifetime matches their storage duration).
When someone says "allocated" they usually refer to storage duration. The language doesn't actually specify exactly when the object's storage duration begins. It is sufficient to require that shall begin at some point before the object's lifetime begins.
For this reason, in general case a static object defined inside a function might never begin its lifetime and, theoretically, it's storage duration does not have to begin either. So, in theory, in might not even get "allocated".
In practice though, all objects with static storage duration ("globals", local statics, etc.) are normally treated equally: they are assigned a specific amount of storage early, at the program's startup.
As an additional note, if a local object with static storage duration requires a non-trivial initialization, this initialization is carried out when the control passes over the definition for the very first time. So in this example
void foo() {
static int *p = new int[100];
}
the dynamic array will never be allocated if the function is never called. And it will be allocated only once if the function is called. This doesn't look like what you are asking about, but I mention this just in case.
Im sure that thats going to be up to the implementation. What MSVC does is - static objects are allocated in the automatic data segment of the EXE or DLL. However, the constructor is only executed the first time the function containing the static is executed.
Yes, actual allocation is compiler dependent, although I think that every compiler just reserves the space in the .static segment of the executable (or the equivalent in its executable file format).
The initialization, however takes place only the firs time that the execution flow encounters the static object, and that is required by the standard.
Beware that initialization of global static objects works in a different way, though.
You can get very good answers to almost every question at the C++ FAQ lite site.
I am also fond of Scott Meyers's "Effective C++".
Depends. If you mean, never called, as in, the function is literally never invoked, then your compiler will probably not allocate it, or even put in the function code. If, however, you made it dependent on, say, user input, and that user input just happened to never come up, then it will probably be pre-allocated. However, you're treading in a minefield here, and it's best just to assume that it is always created by the time control enters the function(s) that refer to it.
Static variables defined on classes (members) or functions are not allocated dynamically on stack during function call, like non static ones. They are allocated in another area of generated code reserved for global and static data. So, if you call the function or not, instantiate classes that contain static members or not, a space to their data will be reserved on program data area anyway.