C++全局变量初始化顺序
C++ global variable initialization order
我不明白下面的代码示例做了什么以及它是如何做到的:
#include <stdio.h>
int f();
int a = f(); // a exists just to call f
int x = 22;
int f() {
++x;
return 123; // unimportant arbitrary number
}
int main() {
printf("%dn", x);
}
运行时,它会打印23
,这是直观的答案。
然而,在C++中,全局变量应该按照定义的顺序初始化。这意味着a
应该在x
之前初始化,因为它是在x
之前定义的。如果是这种情况,那么在初始化x
之前必须调用函数f
,因为对f
的调用是a
定义的一部分。
如果f
确实在x
初始化之前被调用,那就意味着f
将尝试递增x
——结果我真的不确定(很可能是UB,或者一些胡言乱语的值)。然后,在a
被初始化之后,x
将被初始化为22
,并且程序将打印出22
。
显然情况并非如此。但是什么呢?这个代码实际上是做什么的
在评估a = f()
之前,似乎x
被设置为22
,但这意味着初始化的顺序颠倒了(我也可能对什么是初始化或何时初始化有误)。
这个问题有点微妙;有关详细信息,请参阅C++11 3.6.2。
对我们来说重要的是,"具有静态存储持续时间的非局部变量"(通俗地说是"全局变量")的初始化有两个阶段:静态初始化阶段和动态初始化阶段。首先是静态阶段。它看起来像这样:
int a = 0;
int x = 22;
动态初始化随后运行:
a = f();
关键是静态初始化根本不"运行"——它只包括在编译时已知的设置值,因此这些值在执行之前就已经设置好了。初始化int x = 22;
之所以是静态的,是因为初始化器是一个常量表达式。
有些情况下,动态初始化可能被提升到静态阶段(但不必如此),但这不是其中之一,因为它不满足
初始化的动态版本在初始化之前不会更改命名空间范围的任何其他对象的值
当这种吊装发生时,允许产生的初始值与未发生时不同。标准中有这样一个"不确定"初始化的例子。
此外,请考虑:
#include <iostream>
using namespace std;
int f();
int g();
int a = f();
int b = g();
int main() {
cout << a << " " << b;
}
int f() {
b++;
cout << "f" << endl;
return 1;
}
int g() {
cout << "g" << endl;
return 2;
}
输出为:
f
g
1 2
用b = 22;
替换b = g();
会导致打印1 23
。Kerrek SB的回答解释了为什么会这样。
- lambda 作为接受其他参数的参数的初始化顺序
- 大括号或等于初始值设定项初始化顺序
- 类内初始化与构造函数初始化列表的顺序
- C++ 模板中的静态常量初始化顺序
- 如果在 C++ 构造函数中以错误的顺序初始化对象数据,会发生什么类型的错误
- 视觉C++:在 DLL 加载期间,全局变量初始化顺序是否具有确定性?
- 构造函数中没有参数的对象类成员按什么顺序初始化?
- 销毁 pthread 互斥体和 C++ 中的取消初始化顺序
- 线程局部变量的初始化顺序
- 初始化值是否保证通过其自己的地址反映,而不考虑内存顺序
- 类静态变量初始化顺序
- 具有静态存储持续时间的常量初始化变量的初始化顺序
- 解析 CRTP 初始化顺序
- 初始化相等C++的顺序
- 内联初始化的静态 const 类成员的初始化顺序保证
- 使用constexpr的全局初始化顺序
- 初始化与类类型相同的静态成员(静态初始化顺序问题)
- 结构化绑定的标识符是否按顺序初始化?
- c++中的求值顺序初始化数组
- c++标准和C语言在哪里说的是一样的:编译单元(.cpp文件)中的变量是按照声明的顺序初始化的