C ++静态初始化顺序

当我在C ++中使用静态variables时,我经常最终想要初始化一个variables传递给它的构造函数。 换句话说,我想创build相互依赖的静态实例。

在一个.cpp或.h文件中,这不是一个问题:实例将按照它们声明的顺序创build。 但是,如果要用另一个编译单元中的实例初始化静态实例,则该顺序似乎无法指定。 其结果是,根据天气情况,可能发生依赖于另一个的实例被构造,并且仅在之后才构造另一个实例。 结果是第一个实例初始化不正确。

有谁知道如何确保以正确的顺序创build静态对象? 我已经search了很长时间的解决scheme,尝试所有的解决scheme(包括施瓦茨计数器解决scheme),但我开始怀疑是否有一个真正有效的解决scheme。

一个可能性是静态函数成员的技巧:

Type& globalObject() { static Type theOneAndOnlyInstance; return theOneAndOnlyInstance; } 

的确,这确实有效。 令人遗憾的是,您必须编写globalObject()。MemberFunction()而不是globalObject.MemberFunction(),导致有些令人困惑和不雅的客户端代码。

更新:谢谢你的反应。 遗憾的是,我似乎回答了我自己的问题。 我想我必须学会和它一起生活…

你已经回答了你自己的问题。 静态的初始化顺序是未定义的,最简单的方法是在初始化函数中包装初始化(尽pipe静态初始化并不完全重构)。

阅读从https://isocpp.org/wiki/faq/ctors#static-init-order开始的C ++ FAQ项目

也许你应该重新考虑你是否需要这么多的全局静态variables。 虽然它们有时可能是有用的,但通常将它们重构为更小的本地范围要简单得多,特别是如果发现某些静态variables依赖于其他variables。

但是你是对的,没有办法确保一个特定的初始化顺序,所以如果你的心已经设置好了,像上面提到的那样在一个函数中保持初始化可能是最简单的方法。

的确,这确实有效。 令人遗憾的是,您必须编写globalObject()。MemberFunction()而不是globalObject.MemberFunction(),导致有些令人困惑和不雅的客户端代码。

但最重要的是它是有效的,而且这是失败的certificate,即。 绕过正确的用法并不容易。

程序的正确性应该是你的首要任务。 另外,恕我直言,()上面是纯粹的文体 – 即。 完全不重要。

根据你的平台,要小心太多的dynamic初始化。 dynamic初始化器可以进行相对较less的清理工作(请参见此处 )。 您可以使用包含成员不同全局对象的全局对象容器来解决此问题。 因此你有:

 Globals & getGlobals () { static Globals cache; return cache; } 

只有一个调用〜Globals()为了清理你的程序中的所有全局对象。 为了访问一个全球性,你仍然有这样的东西:

 getGlobals().configuration.memberFunction (); 

如果你真的想要,你可以用macros来包装它,以便使用一个macros保存一点点的input:

 #define GLOBAL(X) getGlobals().#X GLOBAL(object).memberFunction (); 

虽然,这只是你最初的解决scheme的语法糖。

大多数编译器(链接器)实际上都支持指定顺序的(不可移植的)方式。 例如,使用visual studio,您可以使用init_seg编译指示将初始化安排到多个不同的组中。 AFAIK没有办法保证在每个组内的命令。 由于这是不可移植的,您可能需要考虑是否可以修复您的devise而不需要它,但是选项已经存在。

尽pipe这个线程的年龄,我想提出我find的解决scheme。 正如很多人之前指出的那样,C ++没有提供静态初始化sorting的机制。 我所build议的是将每个静态成员封装在类的静态方法内部,然后依次初始化成员并以面向对象的方式提供访问。 让我举个例子,假设我们要定义一个名为“Math”的类,在其他成员中包含“PI”:

 class Math { public: static const float Pi() { static const float s_PI = 3.14f; return s_PI; } } 

在第一次调用Pi()方法(在GCC中)时,s_PI将被初始化。 请注意:具有静态存储的本地对象具有与实现有关的生命周期,请参阅6.7.4中的进一步详细信息。

静态关键字 , C ++标准

在一个方法中包装静态将解决订单问题,但它不是像其他人所指出的线程安全,但如果这是一个问题,你可以做到这一点。

 // File scope static pointer is thread safe and is initialized first. static Type * theOneAndOnlyInstance = 0; Type& globalObject() { if(theOneAndOnlyInstance == 0) { // Put mutex lock here for thread safety theOneAndOnlyInstance = new Type(); } return *theOneAndOnlyInstance; }