为什么静态初始化顺序仍未指定

Why is static initialization order STILL unspecified?

本文关键字:未指定 顺序 初始化 静态 为什么      更新时间:2023-10-16

>编译器是否拥有生成所有全局变量的依赖树并为它们创建定义良好且正确的初始化顺序所需的所有信息?我意识到你可以用全局变量编写一个循环依赖关系 - 只使这种情况未定义的行为 - 编译器可以警告并可能出错。

通常,这种事情的原因是编译器制作者会很负担或导致编译速度显着变慢。我没有指标或证据表明这两种情况在这种情况下都不是真的,但我的倾向是两者都不是真的。

嗯,想象一下以下设置,它C++完全有效,但分析起来很棘手:

// TU #1
bool c = coin();

// TU #2
extern bool c;
extern int b;
int a = c ? b : 10;

// TU #3
extern bool c;
extern int a;
int b = c ? 20 : a;

很明显,TU #1 需要先初始化,但然后呢?具有引用到静态的标准解决方案允许您使用标准C++正确编写此代码,但通过修复全局初始化顺序来解决此问题似乎很棘手。

编译器可以处理的部分实际上是定义的:具有静态存储持续时间的对象按照其定义在翻译单元中出现的顺序构造。销毁顺序正好相反。

在翻译单元之间对对象进行排序时,通常不会显式表示对象的依赖关系组。但是,即使显式重新配置了依赖项,它们实际上也没有多大帮助:在小型项目中,具有静态存储持续时间的对象之间的依赖项可以相对容易地管理。事情变得有趣的地方是大型对象,但这些对象更有可能包含表单的初始化

static T global = functionWhichMayuseTheword();

也就是说,在排序有用的情况下,它注定不起作用。

有一种微不足道的方法可以确保对象及时构造,这在C++中甚至是线程安全的(它在 C++03 中不是线程安全的,因为该标准首先没有提到任何线程的概念):使用函数本地static对象并返回对它的引用。这些对象将根据需求构建,但如果它们之间存在依赖关系,这通常是可以接受的:

static T& global() {
    static rc = someInitialization();
    return rc;
}

鉴于有一个简单的解决方法,既没有提案也没有证明提案有效的工作实现,因此更改全局对象初始化方式的状态几乎没有兴趣。更不用说改进对全局对象的支持似乎与使goto变得更好一样有用。

我不是编译器作者,所以对我说的话持保留态度。我认为原因如下。

1)希望保留单独编译的C模型。链接时间分析当然是允许的,但我怀疑他们不想让它成为必需的。

2)Meyers Singleton(特别是现在它已经变得线程安全)提供了一个足够好的替代方案,因为它几乎和全局变量一样易于使用,但提供了您正在寻找的保证。