在我的程序中某个文件的顶部,在所有函数之外,我有这些变量:
namespace {
int foo = foo_func();
}
int bar = bar_func();
如您所知,foo
它是仅对该文件本地的变量,但bar
每个文件都可以访问。
...但是问题:函数什么时候foo_func()
真正bar_func()
运行?这会在main()
运行之前发生,还是可能在稍后的某个时间发生(比如在实际需要这些值之前)?
在我的程序中某个文件的顶部,在所有函数之外,我有这些变量:
namespace {
int foo = foo_func();
}
int bar = bar_func();
如您所知,foo
它是仅对该文件本地的变量,但bar
每个文件都可以访问。
...但是问题:函数什么时候foo_func()
真正bar_func()
运行?这会在main()
运行之前发生,还是可能在稍后的某个时间发生(比如在实际需要这些值之前)?
语言规范声明初始化函数将在调用该翻译单元的任何函数或访问该翻译单元中定义的任何对象之前执行。因此,在一般情况下,这实际上取决于您的定义如何在翻译单元中传播。
初始化是按从上到下的顺序进行的,因此,根据您的定义顺序,bar_func
应该看到已经初始化foo
,但foo_func
应该看到“未初始化”(即零初始化)bar
。
请注意,如果您main
驻留在另一个翻译单元中,则意味着初始化不必在main()
. 但是,如果您尝试访问foo
或bar
从main
(或从其他任何地方)访问,则应保证为定义这些变量的整个翻译单元触发初始化过程。
此外,如果您的初始化程序是常量表达式(constexpr
函数),则可以静态执行整个初始化,这通常意味着变量将以已初始化(编译时初始化)状态开始其生命周期。
使用非constexpr
函数的返回值进行初始化是动态初始化。动态初始化的顺序定义如下(省略一些我认为与您的问题无关的细节):
§3.6.2/2:
具有静态存储持续时间 (3.7.1) 或线程存储持续时间 (3.7.2) 的变量应在任何其他初始化发生之前进行零初始化 (8.5)。
[...]
在单个翻译单元中定义的具有有序初始化的变量应按照它们在翻译单元中的定义顺序进行初始化。如果程序启动线程(30.3),则变量的后续初始化相对于在不同翻译单元中定义的变量的初始化是无序的。否则,变量的初始化相对于在不同翻译单元中定义的变量的初始化是不确定的。
§3.6.2/3:
允许实现将具有静态存储持续时间的非局部变量的初始化作为静态初始化,即使这种初始化不需要静态完成,只要 [Jerry 的总结:它产生的结果与动态完成。]
§3.6.2/4:
具有静态存储持续时间的非局部变量的动态初始化是否在 main 的第一条语句之前完成是实现定义的。如果初始化延迟到 main 的第一个语句之后的某个时间点,它应该发生在与要初始化的变量在同一翻译单元中定义的任何函数或变量的第一次 odr-use (3.2) 之前