C++ 类继承权中的静态初始化顺序

C++ 类继承权中的静态初始化顺序,c++,initialization,static-initialization,initialization-order,C++,Initialization,Static Initialization,Initialization Order,我最近痛苦地意识到了这一点。我想知道,对于父类中的静态成员,子类中的静态成员所需的“初始化顺序在转换单元之间未定义”规则是否仍然适用 例如,假设我们有(为了简洁起见,排除了所有的#警卫和包括) 然后是a的子类 // b.h class B : public A { static int id; }; // b.cpp int B::id = A::register_subclass(); 这里有两个翻译单元,其中一个是静态对象,另一个是初始化时的静态对象。。。这似乎是静态初始化顺序失

我最近痛苦地意识到了这一点。我想知道,对于父类中的静态成员,子类中的静态成员所需的“初始化顺序在转换单元之间未定义”规则是否仍然适用

例如,假设我们有(为了简洁起见,排除了所有的#警卫和包括)

然后是
a
的子类

// b.h
class B : public A {
    static int id;
};

// b.cpp
int B::id = A::register_subclass();
这里有两个翻译单元,其中一个是静态对象,另一个是初始化时的静态对象。。。这似乎是静态初始化顺序失败的一个例子

我的问题是:它真的安全吗


也就是说,我是否保证在初始化
B::id
之前,
A::count
不会包含从
A::count
复制的垃圾?根据我自己的测试,
A
似乎总是先初始化,但我不确定如何在初始化顺序中引入噪声,以增加行为未定义时失败的概率。

通常,依赖基类和派生类的静态初始化顺序是不安全的。不能保证
A
的静态初始化将在
B
之前发生。这就是这个问题的定义

您可以在首次使用习惯用法时使用构造:

更新:然而,博格丹在评论中指出

根据本标准中的[3.6.2],本具体示例中的初始化顺序得到保证。它与继承无关,但实际上
A::count
的初始化是常量初始化,这保证在动态初始化之前完成,这就是
B::id
所使用的

但是,除非你完全掌握了这些内部过程,否则我建议你使用“第一次使用时构造”这个成语

在这种情况下也可以,但是在多线程上下文中要小心像
A::register\u子类
这样的函数。如果多个线程同时调用它,任何事情都可能发生

我想知道,对于父类中的静态成员,子类中的静态成员所需的“初始化顺序在转换单元之间未定义”规则是否仍然适用

是的


静态数据成员与继承层次结构(或者,实际上,它们的封装类)相关的唯一方式是它们的完全限定名;它们的定义和初始化完全不知道/不关心这一点。

否。不保证a.cpp和b.cpp链接到可执行文件的顺序。这就是“初始化命令失败”。(你的链接器可能会使用字母顺序,也可能不会)。@BoPersson我很害怕。谢谢把这个作为一个答案(也许提供一个参考?),我会记下来accepted@BoPersson:答案就在下面,伙计↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓谢谢-这就是我最终使用的解决方案。糟糕的是,有必要在我可怜、简单的小变量周围添加讨厌的静态函数cruft。实际上,根据标准中的[3.6.2],OP的具体示例中的初始化顺序是有保证的。它与继承无关,但实际上
A::count
的初始化是常量初始化,这保证在动态初始化之前完成,这就是
B::id
所使用的<但是,代码>计数+在存在线程的情况下可能会出现问题-可能会同时运行
B::id
和其他一些
C::id
的初始化。cc@stett使用local
static
s的建议通常是合理的,但为了准确起见,我认为在回答中澄清上述细节可能是值得的。−1初始化
inta::count=0
是完全冗余的,因为
A::count
已经初始化为零。即:(1)定义
inta::count就足够了,(2)这确保了示例的安全性。这意味着这个答案的断言“一般来说,这是不安全的”是错误的。@Cheersandhth.-Alf我已经试着更清楚地说明我所说的“一般”是什么意思。
// b.h
class B : public A {
    static int id;
};

// b.cpp
int B::id = A::register_subclass();
// a.h
class A {
private:
    static int& count();
protected:
    static int register_subclass();
};

// a.cpp
int& A::count() {
    static int count = 0;
    return count;
}

int A::register_subclass() {
    return count()++;
}

// b.h
class B : public A {
public:
    static int id;
};

// b.cpp
int B::id = A::register_subclass();