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

事实上,问题来自标准草案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.

这些词是否意味着如果满足这两个条件,则类型的非局部变量可以静态完全初始化(零初始化),以便不调用其构造函数(因为动态版本,通过调用构造函数初始化,可能被静态版本取代)?

最佳答案 在编译/链接期间执行静态初始化.编译器/链接器为静态存储器中的变量分配一个位置,并用正确的字节填充它(字节不需要全为零).程序启动时,静态存储器的那些区域从程序的二进制文件加载,不需要进一步初始化.

例子:

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)因为变异而必须保持动态.

(3)必须保持动态,因为它取决于外部环境/进行系统调用.

(4)可以静态执行.

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

点赞