【问题标题】:What are the rules regarding initialization of non-local statics?关于非局部静态初始化的规则是什么?
【发布时间】:2012-12-05 02:02:16
【问题描述】:

假设我有一个类,其唯一目的是在构造其对象期间产生副作用(例如,向工厂注册一个类):

class SideEffectCauser {
public:
  SideEffectCauser() { /* code causing side-effects */ }
};

还假设我想让一个对象为多个翻译单元中的每一个创建一次这样的副作用。对于每个这样的翻译单元,我希望能够在 .cpp 文件的命名空间范围内放置一个 SideEffectCauser 对象,例如,

SideEffectCauser dummyGlobal;

但是 C++03 标准的 3.6.2/3 建议根本不需要构造这个对象,除非使用 .cpp 文件中的对象或函数,以及诸如this 之类的文章和在线讨论等正如this 所暗示的那样,这些对象有时没有被初始化。

另一方面,Is there a way to instantiate objects from a string holding their class name? 有一个声称可以工作的解决方案,我注意到它是基于使用像 SideEffectCauser 这样类型的对象作为静态数据成员,而不是作为全局数据成员,例如,

class Holder {
  static SideEffectHolder dummyInClass;
};

SideEffectHolder Holder::dummyInClass;

dummyGlobaldummyInClass 都是非局部静态变量,但仔细查看 C++03 标准的 3.6.2/3 会发现该段落仅适用于命名空间范围内的对象。我实际上在 C++03 标准中找不到任何说明何时动态初始化类范围内的非局部静态变量的内容,尽管 9.4.2/7 建议与命名空间中的非局部静态变量相同的规则适用于它们范围。

问题1:在C++03中,有没有理由相信dummyInClassdummyGlobal更有可能被初始化?或者如果没有使用同一翻译单元中的函数或对象,两者都可能未初始化?

问题 2:C++11 有什么变化吗? 3.6.2 和 9.4.2 中的措辞与 C++03 版本不同,但据我所知,对于我上面描述的场景没有指定行为差异。

问题 3:是否有可靠的方法在函数体外部使用 SideEffectHolder 之类的对象来强制产生副作用?

【问题讨论】:

  • 我想我们前段时间讨论过这个问题,C++03 和 C++11 都没有严格要求如果 TU 中没有函数被调用,则必须构造静态,但没有编译器会利用它因为它会破坏每个人的代码......
  • 回答你的第一个问题:在 C++03 中,Schwarz counter 将保证静态类 dummyInClassdummyGlobal 被初始化,无论它们的对象是否被调用。这种方法消除了与初始化或不存在相关的任何不确定性。
  • @KerrekSB:不幸的是,我的问题是由一位同事的经验提出的,他发现静态链接一切正常,但动态链接却不行。有人会想,当通过动态链接引入 TU 时,该 TU 中的非本地静态变量将被动态初始化,但这似乎没有发生,因为该 TU 中没有使用任何内容(并且不会直到非局部静力学产生副作用)。
  • +1 提出了一个很好的问题,但这样做的目的是可疑的。这意味着仅仅链接到目标文件会导致应用程序的行为发生变化,即使应用程序会在没有目标文件的情况下进行链接。
  • @Jan :与 C++03 不同,在 C++11 中,未命名命名空间中的函数具有内部链接,除非另有说明。

标签: c++ c++11


【解决方案1】:

我认为唯一可靠的解决方案是针对特定的编译器和运行时进行设计。没有标准涵盖共享库中全局变量的初始化,我认为这是最复杂的情​​况,因为这在很大程度上取决于加载程序,因此也取决于操作系统。

Q1:没有 Q2:没有任何实际意义 Q3:不是标准的方式

【讨论】:

    【解决方案2】:

    我在 Linux 下使用与 g++/C++11 类似的东西,并按预期注册我的工厂。我不确定为什么你不会调用这些函数。如果要实现您描述的内容,则意味着该单元中的每个函数都必须调用初始化函数。我不太确定如何做到这一点。我的工厂也在命名空间内,尽管它被命名为命名空间。但我不明白为什么它不会被调用。

    namespace snap {
    namespace plugin_name {
    class plugin_name_factory {
    public:
      plugin_name_factory() { plugin_register(this, name); }
    ...
    } g_plugin_name_factory;
    }
    }
    

    请注意,无论如何,在 C++ 中不应再使用 static 关键字。静态定义通常比全局定义要慢。

    【讨论】:

    • static 在 c++11 中已被弃用
    猜你喜欢
    • 1970-01-01
    • 2018-01-18
    • 1970-01-01
    • 2021-10-23
    • 1970-01-01
    • 2013-07-21
    • 1970-01-01
    • 1970-01-01
    • 2013-08-08
    相关资源
    最近更新 更多