In fact, the problem comes from the words in the standard draft N4582:
[basic.start.static/3] An implementation is permitted to perform the initializatio
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.