【问题标题】:C++ static global non-POD: theory and practiceC++静态全局非POD:理论与实践
【发布时间】:2010-12-05 00:28:27
【问题描述】:

我正在阅读 Qt 编码约定文档并看到以下段落:

任何具有构造函数或需要运行要初始化的代码的东西都不能用作库代码中的全局对象,因为它是未定义的,何时运行该构造函数/代码(在首次使用时,在库加载时,在 main( ) 或根本没有)。即使为共享库定义了初始化程序的执行时间,在插件中移动代码或静态编译库时也会遇到麻烦。

我知道theory 说什么,但我不明白“一点也不”的部分。有时我使用非 POD 全局 const 静态变量(例如:QString),但我从未想过它们可能没有被初始化……这是否特定于共享对象/DLL?这只发生在损坏的编译器上吗?

你觉得这条规则怎么样?

【问题讨论】:

  • 如果你不使用它们,你的 QString 可能不会被初始化。但是如果你使用它们,它们将被初始化。即使这是在使用之前(即在对象上调用 a 方法之前)。

标签: c++ qt static initialization shared-libraries


【解决方案1】:

“一点也不”部分只是说 C++ 标准对这个问题保持沉默。它不了解共享库,因此没有说明某些 C++ 功能与这些功能的交互。

在实践中,我已经看到在 Windows、OSX 以及许多版本的 Linux 和其他 Unices 上使用全局非 POD 静态全局变量,无论是在 GUI 和命令行程序中,作为插件还是作为独立应用程序。至少一个项目(使用非 POD 静态全局变量)具有所有这些组合的完整集的版本。我见过的唯一问题是,一些非常旧的 GCC 版本生成的代码在可执行文件停止时调用动态库中此类对象的 dtors,而不是在卸载库时。当然,那是致命的(在库已经消失时调用了库代码),但那已经是差不多十年前的事了。

当然,这仍然不能保证任何事情。

【讨论】:

    【解决方案2】:

    我不认为静态对象的构造函数可以省略。静态库通常只是一堆对象,这些对象在它们被引用的可执行文件 if 中是标记,这可能会让人感到困惑。一些静态对象的设计使得它们不会在其包含的对象之外被引用,因此只有在对它们有其他依赖关系时,才会将对象文件放入可执行文件中。在某些模式中情况并非如此(例如,使用注册自身的静态对象)。

    【讨论】:

    • 我认为您将“静态对象”与“静态库”混淆了。
    • “静态对象”是指“具有静态存储持续时间的对象”。顺便说一句,我发现参考说如果它们的初始化或析构函数有副作用,则无法删除它们:3.7.1/2。
    • 我的意思是静态库在这里很可能不是问题。问题在于动态库。
    【解决方案3】:

    如果静态对象定义在一个没有被引用的对象中,链接器可以完全修剪该对象,包括静态初始化代码。它定期为 libs 这样做(这就是 libc 在 gnu 下使用它的一部分时没有完全链接的原因,例如)。

    有趣的是,我不认为这是特定于图书馆的。即使在主构建中,对象也可能发生这种情况。

    【讨论】:

      【解决方案4】:

      我认为使用带有构造函数的全局对象没有问题。

      它们不应该在其构造函数(或析构函数)中对其他全局对象有任何依赖。

      但是如果它们确实有依赖关系,那么依赖对象必须要么在同一个编译单元中,要么被延迟评估,这样你就可以在使用它之前强制对其进行评估。

      构造函数中的代码也不应该依赖于它何时执行(这与依赖关系有关,但并不完全相同),但您可以安全地假设它至少会被构造(就在方法被调用),而 C++ 保证销毁顺序与实例化相反。

      遵守这些规则并不难。

      【讨论】:

        【解决方案5】:

        C++ 没有定义静态初始化程序对不同编译单元中的对象执行的顺序(顺序在编译单元中定义良好)。

        考虑在不同编译单元中定义了 2 个静态对象 A 和 B 的情况。假设对象 B 在初始化时实际上使用了对象 A。

        在这种情况下,B 可能会首先被初始化,然后调用未初始化的 A 对象。这可能是“一点也不”的意思——当一个对象没有机会先自我初始化时(即使它可能稍后被初始化),它正在被使用。

        我认为动态链接可能会增加我没有想到的复杂性,这会导致对象永远不会被初始化。无论哪种方式,最重要的是静态初始化引入了足够多的潜在问题,应该尽可能避免它,并在你必须使用它的地方非常小心地处理。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-12-11
          • 2017-06-27
          • 2015-06-12
          • 2011-01-17
          • 1970-01-01
          • 2023-03-30
          • 2021-09-06
          • 1970-01-01
          相关资源
          最近更新 更多