如何理解在某些情况下允许实现将非局部变量的动态初始化视为静态初始化?

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

其实问题出在标准草案N4582中的话:

[basic.start.static/3] An implementation is permitted to perform the initialization of a variable with static or thread storage duration as a static initialization even if such initialization is not required to be done statically, provided that

— the dynamic version of the initialization does not change the value of any other object of static or thread storage duration prior to its initialization, and

— the static version of the initialization produces the same value in the initialized variable as would be produced by the dynamic initialization if all variables not required to be initialized statically were initialized dynamically.

这句话的意思是说如果满足这两个条件,一个class类型的非局部变量可能会被完全静态初始化(零初始化),这样它的构造函数就不会被调用(因为动态版本,通过调用构造函数初始化,可能会被静态版本替换)?

在 compilation/linking 期间执行静态初始化。 compiler/linker 为静态内存中的变量分配一个位置,并用正确的字节填充它(字节不需要全为零)。当程序启动时,静态内存的这些区域将从程序的二进制文件中加载,不需要进一步初始化。

示例:

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

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

与静态初始化不同,动态初始化需要 运行在程序启动后使用一些代码来将这样初始化的变量设置为其初始状态。需要是 运行 的代码不需要是构造函数调用。

示例:

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)
}

现在,C++ 标准允许编译器执行将在动态初始化期间执行的计算,前提是这些计算没有副作用。此外,这些计算不能依赖于外部环境。在上面的例子中:

(1) 可以静态执行,因为 strlen() 没有任何副作用。

(2) 必须保持动态,因为它会变异 a.

(3) 必须保持动态,因为它依赖于外部 environment/makes 系统调用。

(4)可以静态执行

(5) 有点棘手,因为浮点计算取决于 FPU 的状态(即舍入模式)。如果告诉编译器不要那么认真地对待浮点运算,那么它可以静态地执行。