【问题标题】:Ensure the construction and destruction order of static variables in c++保证c++中静态变量的构造和销毁顺序
【发布时间】:2015-12-29 00:42:49
【问题描述】:

我正在努力寻找一种好的方法来保证静态变量的构造和销毁顺序。据我所知,静态变量的构造和析构方式如下:

  1. Destruction order of static objects are in the reverse order of their construction.

  2. 如果静态变量在不同的文件中定义为全局空间,那么它们的构造顺序是不能保证的。

  3. 但是,如果在函数中定义了静态变量,则local static variable is constructed when the first time execution hits its declaration

根据上面的规则,我写了如下c++代码,保证静态变量b总是在静态变量a之前被销毁,在我的实验中保证了构造顺序和销毁顺序:

在 A.h 文件中

class A {
 public:
  SomeClass* GetStatic() {
    static SomeClass a;
    return &a;
  }
}

在 B.h 文件中:

#include "A.h"
class B {
 public:
  AnotherClass* GetStatic() {
    A::GetStatic();  // a dummy call to force the static local variable in 
                     // A::GetStatic() get initialized before the b.
    static AnotherClass b;
    return &b;
  }
}

在上面的示例中,我在 static AnotherClass b; 的声明之前放置了一个虚拟调用 A::GetStatic();。如果规则 3 成立,这将确保 ab 之前初始化。并且由于规则1,可以保证ba之前被销毁。

我的问题是:

  1. 我可以知道我所做的事情是正确的还是在某些极端情况下可能出错?
  2. 是否有更好或最好的方法来确保静态变量的构造或销毁顺序?

我还检查了isocpp.org website 以找到确保静态变量的构造和销毁顺序的最佳方法,但该部分仍标记为 TODO: WRITE THIS UP。

【问题讨论】:

标签: c++ static


【解决方案1】:

在您的情况下,您在第一次使用时使用构造,并且您的类的构造函数都不依赖于另一个。从而保证初始化的顺序是A然后B。

在这种情况下,只要您有简单的析构函数,就可以保证破坏顺序是 B->A。这里还有一个elaborate answer

【讨论】:

  • 我能否进一步知道在这种情况下是否保证销毁顺序是B然后A,因为它的构造顺序是A然后B?
  • @keelar 对不起,没有把它放在答案中,这不是第一次阅读时问题的一部分,但也许我错过了。在您的情况下,可以保证,第二种形式的 COFU 不是。
  • 另外值得一读 [this answer][2],尤其是 [the cmets][3]。 [2]:stackoverflow.com/a/9968204/3537677 [3]:stackoverflow.com/questions/9968162/…
【解决方案2】:

很遗憾,但您目前所做的是“最先进的”。

另一个有用的谷歌技术:

#pragma init_seg(XXX) - 适用于 Windows 下的 MSVS 和 Intel C++

__attribute__ ((init_priority(XXX)) - 在 GCC 和 clang 中工作

另外,我必须警告您,您的本地 static 技巧不是线程保存(至少在 MSVC、Intel C++、clang 和 gcc 中),因为它是通过检查和设置全局变量来实现的。

【讨论】:

  • 当然在最近的 gcc 和 clang 中,它是线程安全的。
  • 如果先调用A::GetStatic(),则在b之前构造a。如果先调用B::GetStatic(),那么在内部它会先调用A::GetStatic(),然后声明b.我能知道它可能在哪里引入线程安全问题吗?
  • 它在 VS 2015 中是线程安全的。见这里:stackoverflow.com/questions/28096970/…
  • 您还链接到 g++ 4.4.7,它是 C++11 之前的版本。接受-std=c++11 的第一个版本是 4.7。但根据this tableg++ 自 4.3 以来已正确实现。
  • @M.M 我不得不承认你是对的。我太快得出关于 gcc 的结论。即使第一个测试没有被保护,它只是为了加速而完成的,因为在 T 的构造函数周围有一个适当的保护。将检查其他编译器。
猜你喜欢
  • 2017-12-07
  • 2013-12-19
  • 1970-01-01
  • 2013-01-19
  • 1970-01-01
  • 1970-01-01
  • 2018-05-02
相关资源
最近更新 更多