C++静态初始化顺序

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1005685/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 18:22:44  来源:igfitidea点击:

C++ static initialization order

c++static-variablesstatic-order-fiascoinitialization-order

提问by Dimitri C.

When I use static variables in C++, I often end up wanting to initialize one variable passing another to its constructor. In other words, I want to create static instances that depend on each other.

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

Within a single .cpp or .h file this is not a problem: the instances will be created in the order they are declared. However, when you want to initialize a static instance with an instance in another compilation unit, the order seems impossible to specify. The result is that, depending on the weather, it can happen that the instance that depends on another is constructed, and only afterwards the other instance is constructed. The result is that the first instance is initialized incorrectly.

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

Does anyone know how to ensure that static objects are created in the correct order? I have searched a long time for a solution, trying all of them (including the Schwarz Counter solution), but I begin to doubt there is one that really works.

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

One possibility is the trick with the static function member:

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

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

Indeed, this does work. Regrettably, you have to write globalObject().MemberFunction(), instead of globalObject.MemberFunction(), resulting in somewhat confusing and inelegant client code.

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

Update:Thank you for your reactions. Regrettably, it indeed seems like I have answered my own question. I guess I'll have to learn to live with it...

更新:感谢您的反应。遗憾的是,我确实好像已经回答了我自己的问题。我想我必须学会忍受它......

采纳答案by laalto

You have answered your own question. Static initialization order is undefined, and the most elegant way around it (while still doing static initialization i.e. not refactoring it away completely) is to wrap the initialization in a function.

你已经回答了你自己的问题。静态初始化顺序是未定义的,围绕它的最优雅的方法(同时仍然进行静态初始化,即不完全重构它)是将初始化包装在一个函数中。

Read the C++ FAQ items starting from https://isocpp.org/wiki/faq/ctors#static-init-order

https://isocpp.org/wiki/faq/ctors#static-init-order开始阅读 C++ 常见问题解答项目

回答by Jesse Beder

Maybe you should reconsider whether you need so many global static variables. While they can sometimes be useful, often it's much simpler to refactor them to a smaller local scope, especially if you find that some static variables depend on others.

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

But you're right, there's no way to ensure a particular order of initialization, and so if your heart is set on it, keeping the initialization in a function, like you mentioned, is probably the simplest way.

但是您是对的,没有办法确保特定的初始化顺序,因此,如果您愿意,将初始化保存在函数中,就像您提到的那样,可能是最简单的方法。

回答by Richard Corden

Indeed, this does work. Regrettably, you have to write globalObject().MemberFunction(), instead of globalObject.MemberFunction(), resulting in somewhat confusing and inelegant client code.

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

But the most important thing is that it works, and that it is failure proof, ie. it is not easy to bypass the correct usage.

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

Program correctness should be your first priority. Also, IMHO, the () above is purely stylistic - ie. completely unimportant.

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

Depending on your platform, be careful of too much dynamic initialization. There is a relatively small amount of clean up that can take place for dynamic initializers (see here). You can solve this problem using a global object container that contains members different global objects. You therefore have:

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

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

There is only one call to ~Globals() in order to clean up for all global objects in your program. In order to access a global you still have something like:

只需调用一次 ~Globals() 即可清除程序中的所有全局对象。为了访问全局,您仍然有类似的东西:

getGlobals().configuration.memberFunction ();

If you really wanted you could wrap this in a macro to save a tiny bit of typing using a macro:

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

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

Although, this is just syntactic sugar on your initial solution.

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

回答by Dolphin

Most compilers (linkers) actually do support a (non-portable) way of specifying the order. For example, with visual studio you can use the init_segpragma to arrange the initialization into several different groups. AFAIK there is no way to guarantee order WITHIN each group. Since this is non-portable you may want to consider if you can fix your design to not require it, but the option is out there.

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

回答by FabioDch

dispite the age of this thread, I would like to propose the solution I've found. As many have pointed out before of me, C++ doesn't provide any mechanism for static initialization ordering. What I propose is to encapsule each static member inside a static method of the class that in turn initialize the member and provide an access in an object-oriented fashion. Let me give you an example, supposing we want to define the class named "Math" which, among the other members, contains "PI":

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

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

s_PI will be initialized the first time Pi() method is invoked (in GCC). Be aware: the local objects with static storage have an implementation dependent lifecyle, for further detail check 6.7.4 in 2.

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

Static keyword, C++ Standard

静态关键字C++ 标准

回答by Ray

Wrapping the static in a method will fix the order problem, but it isn't thread safe as others have pointed out but you can do this to also make it thread if that is a concern.

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

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