C++ 如何理解在某些情况下允许实现将非局部变量的动态初始化视为静态初始化?
事实上,问题来自标准草案N4582中的文字: [basic.start.static/3]允许实现以静态或线程存储持续时间作为静态初始化来执行变量的初始化,即使不需要静态完成此类初始化,但前提是:C++ 如何理解在某些情况下允许实现将非局部变量的动态初始化视为静态初始化?,c++,static-initialization,C++,Static Initialization,事实上,问题来自标准草案N4582中的文字: [basic.start.static/3]允许实现以静态或线程存储持续时间作为静态初始化来执行变量的初始化,即使不需要静态完成此类初始化,但前提是: -初始化的动态版本在初始化之前不会更改任何其他静态或线程存储持续时间对象的值,并且 -如果所有不需要静态初始化的变量都是动态初始化的,则初始化的静态版本会在初始化变量中生成与动态初始化相同的值 这些词是否意味着,如果满足这两个条件,类类型的非局部变量可以完全静态初始化(零初始化),这样就不会调用其构造
-初始化的动态版本在初始化之前不会更改任何其他静态或线程存储持续时间对象的值,并且 -如果所有不需要静态初始化的变量都是动态初始化的,则初始化的静态版本会在初始化变量中生成与动态初始化相同的值
这些词是否意味着,如果满足这两个条件,类类型的非局部变量可以完全静态初始化(零初始化),这样就不会调用其构造函数(因为通过调用构造函数初始化的动态版本可能会被静态版本替换)?编译/链接期间执行静态初始化。编译器/链接器在静态内存中为变量分配一个位置,并用正确的字节填充它(字节不需要全部为零)。当程序启动时,这些静态内存区域从程序的二进制文件加载,无需进一步初始化 示例:
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)
}
与静态初始化不同,动态初始化需要在程序启动后运行一些代码,以将初始化后的变量设置为初始状态。需要运行的代码不需要是构造函数调用
示例:
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的状态(即舍入模式)。如果编译器被告知不要那么认真地对待浮点运算,那么它可以静态地执行。如果一个类有一个用户定义的构造函数,它肯定会被调用。我不清楚在调用构造函数之前是否进行了零初始化。这只是我的解释,但我怀疑在“调用”构造函数之前是否需要进行零初始化-构造函数的目的之一是初始化对象占用的内存。静态和动态初始化规则影响不同对象的构造顺序。不过,这些规则是递归的,因为对象具有基,并且包含在构造函数调用之前初始化的成员。非类成员(例如,
int
)很可能在该过程中被初始化为零。@RSahu感谢您的回答,但我的观点是,为什么一定会调用构造函数?调用构造函数是动态初始化中的一种行为,但正如标准中所说,允许将动态初始化实现为静态初始化。我不知道实现如何保证用户定义的构造函数不会更改另一个静态或线程存储持续时间对象的值。谢谢您的回答。因此,在您的示例中,如果c是静态初始化的,那么当c.i直接设置为123时,构造函数会被跳过吗?如果是这样,根据[class.cdtor]中的第一段:“对于具有非平凡构造函数的对象,在构造函数开始执行之前引用对象的任何非静态成员或基类会导致未定义的行为”,在您的示例中,任何对c.i的进一步访问都会导致未定义的行为,尽管它有一个明确的值123,真不可思议!或者在上述分析中是否存在一些错误?对于示例代码,可以认为构造函数已执行,因为其唯一作用是将c.i
设置为123
。编译器稍微重新安排了如何完成这一点只是一个实现细节。如果存在副作用呢?[basic.start.static/3]似乎对副作用没有任何要求。“不改变任何其他对象的值”是指副作用