Is Static Object Guaranteed to Be Initialized

Is static object guaranteed to be initialized

I think that all this wording is there to describe what will happen in dynamic loaded libraries, but without explicitly naming them.

To summarize how I interpret it: a non-local variable with static storage duration and dynamic initialization will:

  1. be initialized before the first odr-use of anything in its translation unit;
  2. possibly, before starting main, but possibly after it.

I interpret the footnote 34 as (but remember that footnotes are not normative):

When anything in a TU is ord-used, then every non-local variable with static storage duration having initialization with side-effects must be initialized, even the variables that are not odr-used.

So, if there is a TU where nothing is ord-used, then its dynamic initializations may not happen.

Example

h1.h

extern int count;
struct S
{
S();
};

h1.cpp

#include "h1.h"

int count;
S::S()
{
++count;
}

h2.cpp

#include "h1.h"
S s;

main.cpp

#include "h1.h"
#include <stdio.h>
int main()
{
printf("%d\n", count);
}

This could print 0 or 1: since anything in TU h2 is never odr-used, it is unspecified when the code initialization of s will be done, if at all.

Naturally, sane compilers will initialize s before main, so it will surely print 1:

$ g++ main.cpp h2.cpp h1.cpp -o test1
$ ./test1
1

Now, imagine that h2.cpp is in a shared library:

$ g++ -shared -fPIC h2.cpp -o h2.so

And the main file is now:

main2.cpp

#include "h1.h"
#include <dlfcn.h>
#include <stdio.h>

int main()
{
printf("%d\n", count);
dlopen("./h2.so", RTLD_NOW);
printf("%d\n", count);
return 0;
}

Compile and run:

$ g++ -shared -fPIC h2.cpp -o h2.so
$ g++ -rdynamic main.cpp h1.cpp -ldl -o test2
$ ./test2
0
1

See? The initialization of s has been delayed! The nice part is that it is impossible to reference anything in the dynamic loaded library without first loading it, and loading it will trigger the dynamic initialization. So all is well.

If you think that using dlopen is cheating, remember that there are compilers that support delay loading shared libraries (VC++ for example), where the system call to load the library will be generated automatically by the compiler just the first time it is needed.

Is initialization of static member of a class guaranteed before initialization of a static object of that class?

In the code, would mFunc be initialized to nullptr before myClassObj gets created? The reason for the query is that if the order is not guaranteed, then mFunc may get initialized again to nullptr.

The answer to the question is "Yes".

Setting aside the issue of initialization of thread specific objects, initialization of non-local variables is carried out in the following order.

  1. All variables are zero-initialized (order not specified). This is called zero initialization.
  2. All variables that can be initialized using constant values are initialized. This is called constant initialization.

Those ( 1 and 2 above) are called static initialization.

After that, dynamic initialization is performed.

In your case, MyClass::mFunc is initialized using constant initialization while myClassObj is initialized using dynamic initialization. Hence, the former is guaranteed to be initialized first.

More on this topic can be found at https://timsong-cpp.github.io/cppwp/n3337/basic.start.init.

Is static variable guaranteed to be initialized when used by static methods in the same translation unit?

Short answer: No, global initialization has nothing to do with static methods.

Here's a simple scenario that illustrates why: what if the constructor of Foo invoked doSth()?

If you need that guarantee, you need to use a function-scope static variable.

Are static data members initialized before all class objects?

If you were to make the constructor a non-inline function, yes, it would be guaranteed to be the value you expect.

k will be subject to constant initialization (on account of the constant initializer), while a's initialization is dynamic. All static initialization happens before dynamic initialization of static objects. But even if k was initialized dynamically:

[basic.start.dynamic] (emphasis mine)

4 It is implementation-defined whether the dynamic initialization
of a non-local non-inline variable with static storage duration is
sequenced before the first statement of main or is deferred. If it
is deferred, it strongly happens before any non-initialization odr-use
of any non-inline function or non-inline variable defined in the same
translation unit as the variable to be initialized
. It is
implementation-defined in which threads and at which points in the
program such deferred dynamic initialization occurs.

And a non-inline constructor qualifies for such a function. This is the basis for the Schwarz Counter technique.

But in your example, the c'tor is an inline function. So it's only due to constant initialization that you get 666. Should the initializer not be a constant expression, a would be undergo dynamic initialization before k according to declaration order in the same TU.

Are uninitialized members of partially-defined static objects guaranteed initialized to 0?

All remaining elements are initialized to zero (for arithmetic types) or a null pointer (for pointers). C 2018 6.7.9 21 says:

If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.

6.7.9 10 says objects with static storage duration are, effectively, initialized with zero:

… If an object that has static or thread storage duration is not initialized explicitly, then:

— if it has pointer type, it is initialized to a null pointer;

— if it has arithmetic type, it is initialized to (positive or unsigned) zero;

— if it is an aggregate, every member is initialized (recursively) according to these rules, and any padding is initialized to zero bits;

— if it is a union, the first named member is initialized (recursively) according to these rules, and any padding is initialized to zero bits;

When are static C++ class members initialized?

The standard guarantees two things - that objects defined in the same translation unit (usually it means .cpp file) are initialized in order of their definitions (not declarations):

3.6.2

The storage for objects with static storage duration (basic.stc.static) shall be zero-initialized (dcl.init) 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. Objects of POD types (basic.types) with static storage duration initialized with constant expressions (expr.const) shall be initialized before any dynamic initialization takes place. Objects with static storage duration defined in namespace scope in the same translation unit and dynamically initialized shall be initialized in the order in which their definition appears in the translation unit.

The other guaranteed thing is that initialization of static objects from a translation unit will be done before use of any object or function from this translation unit:

It is implementation-defined whether or not the dynamic initialization (dcl.init, class.static, class.ctor, class.expl.init) 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.

Nothing else i guaranteed (especially order of initialization of objects defined in different translation units is implementation defined).

EDIT
As pointed in Suma's comment, it is also guaranteed that they are initialized before main is entered.

Is static initialization guaranteed here?

Yes, the Standard says f will be constant initialized:

[basic.start.init]/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:

  • ... [a case for references]

  • 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;

  • ... [a case for objects initialized without a constructor call]

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.

The initialization full-expression is simply the call of Foo's default constructor, which is a constant expression.

MSVC is wrong to emit code to initialize f.

When do function-level static variables get allocated/initialized?

I was curious about this so I wrote the following test program and compiled it with g++ version 4.1.2.

include <iostream>
#include <string>

using namespace std;

class test
{
public:
test(const char *name)
: _name(name)
{
cout << _name << " created" << endl;
}

~test()
{
cout << _name << " destroyed" << endl;
}

string _name;
};

test t("global variable");

void f()
{
static test t("static variable");

test t2("Local variable");

cout << "Function executed" << endl;
}

int main()
{
test t("local to main");

cout << "Program start" << endl;

f();

cout << "Program end" << endl;
return 0;
}

The results were not what I expected. The constructor for the static object was not called until the first time the function was called. Here is the output:

global variable created
local to main created
Program start
static variable created
Local variable created
Function executed
Local variable destroyed
Program end
local to main destroyed
static variable destroyed
global variable destroyed


Related Topics



Leave a reply



Submit