实际上,问题出在标准草案N4582中:

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

最佳答案

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

例子:

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)必须保持动态,因为它取决于外部环境/进行系统调用。

(4)可以静态执行。

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

10-08 04:08