C++ 静态初始化顺序

发布于 2024-07-24 23:34:35 字数 674 浏览 11 评论 0原文

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

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

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

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

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

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

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

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.

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.

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.

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.

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...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

一刻暧昧 2024-07-31 23:34:36

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

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

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

黑凤梨 2024-07-31 23:34:36

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

但你是对的,没有办法确保初始化的特定顺序,因此,如果你决心这样做,那么将初始化保留在函数中,就像你提到的那样,可能是最简单的方法。

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.

橘寄 2024-07-31 23:34:36

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

Most compilers (linkers) actually do support a (non-portable) way of specifying the order. For example, with visual studio you can use the init_seg pragma 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.

谁许谁一生繁华 2024-07-31 23:34:36

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

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

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

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

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

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

getGlobals().configuration.memberFunction ();

如果您确实想要,您可以将其包装在宏中以节省使用宏的少量输入:

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

尽管如此,这只是您初始解决方案的语法糖。

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

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:

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.

川水往事 2024-07-31 23:34:36

尽管该线程已经存在了很长时间,但我还是想提出我找到的解决方案。
正如许多人之前指出的那样,C++ 不提供任何静态初始化排序机制。 我的建议是将每个静态成员封装在类的静态方法中,该方法依次初始化该成员并以面向对象的方式提供访问。
让我举个例子,假设我们要定义名为“Math”的类,其中包含“PI”:

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

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

静态关键字C++ 标准

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":

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.

Static keyword, C++ Standard

徒留西风 2024-07-31 23:34:36

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

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

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文