When Are Static C++ Class Members Initialized

How to initialize private static members in C++?

The class declaration should be in the header file (Or in the source file if not shared).

File: foo.h

class foo
{
private:
static int i;
};

But the initialization should be in source file.

File: foo.cpp

int foo::i = 0;

If the initialization is in the header file then each file that includes the header file will have a definition of the static member. Thus during the link phase you will get linker errors as the code to initialize the variable will be defined in multiple source files.
The initialisation of the static int i must be done outside of any function.

Note: Matt Curtis: points out that C++ allows the simplification of the above if the static member variable is of const integer type (bool, char, char8_t [since C++20], char16_t, char32_t, wchar_t, short, int, long, long long, or any implementation-defined extended integer types, including any signed, unsigned, and cv-qualified variants.). You can then declare and initialize the member variable directly inside the class declaration in the header file:

class foo
{
private:
static int const i = 42;
};

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.

Why static members need to be initialized out of the class

What you call initialization is really a definition.

And the reason is that definitions can only be done once is a single translation unit.

If the static member variable were defined in the header file it could be defined multiple times breaking the one definition rule.

Or the compiler would not know which translation unit to put the definition in, since it doesn't know anything about other possible translation units.

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.

How to declare and initialize a static member in a class?

One can definitely have class static members which are not CV-qualified (non const and not volatile). It is just that one should not initialize them (give them value) when one declare them inside the class, based on current ISO C++ regulations. In Comparison, it is OK to do so for non static data members(regardless of CV-qualification) Since C++11.

Because static data members do not belong to any object, with the right access they can be assigned (and if they are not constant, they can be manipulated) outside of the class(keeping in mind the right scope operator). Also regardless of public/private declaration and CV-qualification, static data members can be initialized outside their class.

So one way for initializing static data members, is to do so in the same block-scope/namespace where their classes(outer class in case of sub-classes) are situated, but not inside any class scope.

For example:

class Graph {
public:
class Node {
public:
static int maxNumberOfNeighbors;
.
.
.
};
.
.
.
};

int Graph::Node::maxNumberOfNeighbors = 4;
//also int Graph::Node::maxNumberOfNeighbors(4);


Good luck!

Is a static member initialized before the constructor is called?

"Is there any scenario where the constructor of Test is called before
the map is initialized?" Of course. All that is required is that there
is a static instance of Test in some other translation unit than the
one in which the map is defined. (Where the code for the constructor of
Test is defined is irrelevant. What counts is where the static
instance of Test is defined.)

There are other possible scenarios as well: the constructor of some
other static object uses a local instance of Test, for example.

The usual solution for this problem is to use a factory method for the
map:

std::map<std::string, Test*>& Test::registry()
{
static std::map<std::string, Test*> theOneAndOnly;
return theOneAndOnly;
}

This will cause the map to be constructed the first time it is needed.

And which compiler are you using? You can't specify an initializer for
a static member in the class definition unless the member is const and
has integral or enum type.

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.

Static member initialization order within a single C# class

In short, don't do this.

Standard ECMA-334 C# Language Specification

15.5.6.2 Static field initialization

The static field variable initializers of a class correspond to a
sequence of assignments that are executed in the textual order in
which they appear in the class declaration
(§15.5.6.1). Within a
partial class, the meaning of "textual order" is specified by
§15.5.6.1. If a static constructor (§15.12) exists in the class,
execution of the static field initializers occurs immediately prior to
executing that static constructor. Otherwise, the static field
initializers are executed at an implementation-dependent time prior to
the first use of a static field of that class

The fix is to :

  • Put them in the order and use Static Constructor,
  • or just Initialise them in a Static Constructor in turn giving you the ability to control the order of initialisation (given the above information).

Personally i suggest to Initialise them in a Static Constructor, it seems to make it more concrete and understandable, and less likely to be bumped in refactoring



Related Topics



Leave a reply



Submit