What Is Dynamic Initialization of Object in C++

What is dynamic initialization of object in c++?

Dynamic initialization is that in which initialization value isn't known at compile-time. It's computed at runtime to initialize the variable.

Example,

int factorial(int n)
{
if ( n < 0 ) return -1; //indicates input error
else if ( n == 0 ) return 1;
else return n * factorial(n-1);
}

int const a = 10 ; //static initialization
//10 is known at compile time. Its 10!

int const b = factorial(8); //dynamic initialization
//factorial(8) isn't known at compile time,
//rather it's computed at runtime.

That is, static-initialization usually involves constant-expression (which is known at compile-time), while dynamic-initialization involves non-constant expression.

static int c;//this is also static initialization (with zero)!

§3.6.2/1 from the C++ Standard (2003) says,

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
.

So there are two kind of initializations:

  • Static initialization : Its either zero-initialization or initialization with a constant expression
  • Any other initialization is dynamic initialization.

Also note that the same variable can be dynamically-initialized after it has been statically-initialized. For example, see this code:

int d = factorial(8);
int main()
{
}

Since d is a global variable, it has static storage. That means, according to §3.6.2.1 it's initialized to 0 at the static-initialization phase which occurs before any other initialization takes place. Then later, at runtime, it's dynamically-initialized with the value returned from the function factorial().

That means, global objects can be initialized twice: once by static initialization (which is zero-initialization) and later, at runtime, they can be dynamically-initialized.

why dynamic initialization occur before static initialization in gcc

b has dynamic initialization, not static initialization.

As already explained by your quote of [basic.start.static]/2, b has static initialization only if the full-expression of its initializer, which is the execution of the Constant(int) constructor, is a constant expression.

In [expr.const]/2, we read:

An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:

  • ...

  • an invocation of a function other than a constexpr constructor for a literal class, a constexpr function, or an implicit invocation of a trivial destructor ([class.dtor]) [ Note: Overload resolution is applied as usual  —  end note ] ;

  • ...

Here the evaluation of the constructor "following the rules of the abstract machine" includes the constructor body. And since the initializer is 0, that evaluation would invoke std::operator<<(std::ostream&, const char*), which is not constexpr. So the initializer's full expression is not a core constant expression and is not a constant expression.

And of course, though it's not the strictly technical definition, the entire point of "constant expression" is to define when we're guaranteed that the compiler can deal with something at compile time. And writing to the program's standard output certainly won't happen at compile time.

cppreference.com is a good resource that tries to be as accurate as possible, but it does not substitute for the authority of the actual Standard. That quote about constant initialization using a class constructor is incorrect for C++14 and C++17. I suspect it's actually left over from C++11, in which the body of a constexpr constructor was not allowed to evaluate any function calls at all, and [expr.const] similarly described requirements on uses of constexpr constructors within a core constant expression in terms of the member initializers.

Dynamic initialization phase of static variables

I believe the intention here is to allow dynamic load libraries.

Static variables defined in the libraries are not guaranteed to be initialized before main, but must happen before anything in the specific library is used.

Dynamic Initialization

The definitive answer is that all compilers do static initialization
before main, unless the objects are in a DLL which is loaded later.
In practice, it's (almost) impossible to meet the requirements in the
text you cite otherwise. (Think of what happens if there is a cycle.)

Dynamic initialization phase of static variables

I believe the intention here is to allow dynamic load libraries.

Static variables defined in the libraries are not guaranteed to be initialized before main, but must happen before anything in the specific library is used.

How to comprehend that an implementation is permitted to treat dynamic initialization of non-local variable as static initialization in some cases?

Static initialization is performed during compilation/linking. The compiler/linker assigns a location to the variable in the static memory and fills it with the correct bytes (the bytes don't need to be all zeros). When the program starts, those regions of the static memory are loaded from the program's binary file and no further initialization is required.

Examples:

namespace A {
// statically zero-initialized
int a;
char buf1[10];

// non-zero initialized
int b = 1;
char date_format[] = "YYYY-MM-DD";
}

Unlike static initialization, dynamic initialization requires running some code after program start-up to set thus initialized variables to their initial state. The code that needs to be run doesn't need to be a constructor call.

Examples:

namespace B {
int a = strlen(A::date_format); (1)
int b = ++a; (2)

time_t t = time(); (3)

struct C {
int i;

C() : i(123) {}
};

C c; (4)

double s = std::sqrt(2); (5)
}

Now, the C++ standard allows the compiler to perform the computations that would be carried out during dynamic initialization, provided that those computations do not have side effects. Besides, those computations must not depend on external environment. In the above example:

(1) can be performed statically since strlen() doesn't have any side-effects.

(2) must stay dynamic since it mutates a.

(3) must stay dynamic since it depends on external environment/makes system calls.

(4) can be performed statically.

(5) is a little tricky, since floating point computation depends on the state of the FPU (namely, rounding mode). If the compiler is told not to treat floating point arithmetic that seriously, then it can be performed statically.



Related Topics



Leave a reply



Submit