在给定的翻译单元中,文件级静态变量的顺序是否总是相同的?

5
我有一个程序分成两个源文件: < p> example.cpp
#include <iostream>

class A {
 public:
   A(int x) {
      ::std::cout << "In A(" << x << ")\n";
   }
};

static A first(1);
static A second(2);

example__main.cpp

int main(int argc, const char *argv[])
{
   return 0;
}

这个程序的输出是否保证是:
In A(1)
In A(2)

在所有平台和编译器上都是这样吗?如果是,标准在哪里说了这个?如果我使用命名空间,并且firstsecond出现在不同的命名空间中,是否会有影响?如果它们不是静态的,并且我使用匿名命名空间呢?

简短的回答是肯定的,通常的警告是“不要依赖它,因为你可能想将其重构为两个不同的文件”,通常的解决方法是懒初始化单例/实现对象,我会让语言专家引用《书》中相关的诗句。 - Alexandre C.
@AlexandreC. - 在这种情况下,一些宏(我知道很糟糕)被用来将它们粘在一起。按照您所描述的方式进行重构将不会发生,或者至少当涉及到分离的宏时,如果它不起作用,也不会让任何人感到惊讶。 - Omnifarious
2个回答

5
是的,如果在同一翻译单元中声明,则为非局部静态对象定义了初始化顺序。
从C++03开始,
(3.6/2)在命名空间范围内定义具有静态存储期限并且动态初始化的对象必须按照它们在翻译单元中的定义出现的顺序进行初始化。[注意:8.5.1描述了聚合成员初始化的顺序。本地静态对象的初始化在6.7中描述。]

3
在一个翻译单元内,全局变量的初始化分为几个阶段:
首先,所有具有“静态初始化”的变量按照声明的顺序进行初始化(见下文)。
然后,所有“有序动态初始化”都按照它们的声明顺序执行。
还有“无序动态初始化”,它们与其他动态初始化“不可排序”(但始终在静态初始化之后)。
静态和有序动态初始化全局变量的销毁反向进行(而无序的则再次“不可排序”,但在静态初始化之前)。跨TUs的相对初始化顺序是未指定的。
简单解释一下术语:如果全局变量要么被初始化为常量(对于构造函数调用,这需要constexpr构造函数),要么没有初始化器且声明为static(这使它被零初始化),则全局变量被“静态初始化”:static int a; Foo b(1, true, Blue);。另一方面,如果初始化程序不是任何“常量”,例如函数调用或非constexpr构造函数,则该对象将“动态初始化”。大多数普通的动态初始化全局变量都是“有序的”;唯一的“无序的”是模板专业化的静态成员等等。
(请注意,在C++11中,由于现在明确关注于线程本地存储和在线程开始时初始化,所有这些都变得更加详细。)

@MatteoItalia:你所说的“动态的”是什么意思? - Kerrek SB
静态初始化是指零初始化和常量初始化的结合;所有其他的初始化都属于动态初始化。在进行任何动态初始化之前,必须先执行静态初始化。 [basic.start.init] ¶2 - Matteo Italia
外部常量是否真的存在呢?:S - Matteo Italia
@MatteoItalia:是的,当然——它只是一个普通的全局变量,是常量。但是常量全局变量默认为static,所以您需要使用extern来覆盖。 - Kerrek SB
@MatteoItalia - 我相信他们会的。 :-) - Omnifarious
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接