繁体   English   中英

C++ static 初始化命令

[英]C++ static initialization order

当我在 C++ 中使用 static 变量时,我常常最终想要初始化一个变量,将另一个变量传递给它的构造函数。 也就是说,我要创建static个相互依赖的实例。

在 single.cpp 或 .h 文件中,这不是问题:实例将按照声明的顺序创建。 但是,当你想用另一个编译单元中的实例初始化一个 static 实例时,顺序似乎无法指定。 结果是,根据天气情况,可能会构建依赖于另一个实例的实例,然后才构建另一个实例。 结果是第一个实例初始化不正确。

有谁知道如何确保以正确的顺序创建 static 个对象? 我已经搜索了很长时间的解决方案,尝试了所有的解决方案(包括 Schwarz Counter 解决方案),但我开始怀疑是否有一个真正有效的解决方案。

一种可能性是 static function 成员的把戏:

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

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

更新:感谢您的反应。 遗憾的是,看起来我确实回答了我自己的问题。 我想我必须学会忍受它……

你已经回答了你自己的问题。 Static 初始化顺序未定义,最优雅的方法(同时仍在进行 static 初始化,即不完全重构它)是将初始化包装在 function 中。

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

也许你应该重新考虑是否需要那么多的全局 static 变量。 虽然它们有时很有用,但通常将它们重构为较小的本地 scope 会简单得多,尤其是当您发现某些 static 变量依赖于其他变量时。

但你是对的,没有办法确保特定的初始化顺序,所以如果你愿意,将初始化保留在 function 中,就像你提到的那样,可能是最简单的方法。

大多数编译器(链接器)实际上支持一种(不可移植的)指定顺序的方式。 例如,对于 visual studio,您可以使用init_seg pragma 将初始化安排到几个不同的组中。 AFAIK 无法保证每个组内的顺序。 由于这是不可移植的,您可能需要考虑是否可以修复您的设计以不需要它,但选项就在那里。

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

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

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

根据您的平台,注意过多的动态初始化。 对于动态初始值设定项,可以进行相对少量的清理(参见此处)。 您可以使用包含不同全局对象成员的全局 object 容器来解决此问题。 因此你有:

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

只有一次调用 ~Globals() 才能清理程序中的所有全局对象。 为了访问全局,你仍然有类似的东西:

getGlobals().configuration.memberFunction ();

如果你真的想要,你可以将它包装在一个宏中,以使用宏节省一点点输入:

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

虽然,这只是您初始解决方案的语法糖。

尽管这个线程的年龄,我想提出我找到的解决方案。 正如我之前许多人指出的那样,C++ 没有为 static 初始化排序提供任何机制。 我的建议是将每个 static 成员封装在 class 的 static 方法中,该方法依次初始化成员并以面向对象的方式提供访问权限。 举个例子,假设我们要定义名为“Math”的 class,其中包含“PI”:

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

s_PI 将在第一次调用 Pi() 方法时初始化(在 GCC 中)。 请注意:具有 static 存储空间的本地对象具有依赖于实现的生命周期,有关详细信息,请查看2中的 6.7.4。

Static 关键字C++ 标准

将 static 包装在一个方法中将解决顺序问题,但它不是线程安全的,正如其他人所指出的那样,但如果这是一个问题,您可以这样做以使其成为线程。

// 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;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM