[英]Static initialization order in class heirarchy
我最近痛苦地意識到靜態初始化命令Fiasco 。 我想知道,如果在翻譯單元中“初始化順序未定義”的規則仍然適用於父類中的靜態成員,而子類中的靜態成員則需要這樣。
例如,假設我們有(為簡潔起見,所有#wards和包括)
// a.h
class A {
static int count;
static int register_subclass();
};
// a.cpp
int A::count = 0;
int A::register_subclass() {
return count ++;
}
然后是A
的子類,
// b.h
class B : public A {
static int id;
};
// b.cpp
int B::id = A::register_subclass();
這里有兩個轉換單元,其中一個靜態對象在初始化中依賴於另一個靜態對象...它似乎可能是靜態初始化順序fiasco的一個實例。
我的問題是: 它真的安全嗎?
也就是說,我保證B::id
在初始化之前不會包含從A::count
復制的垃圾嗎? 根據我自己的測試, A
似乎總是先被初始化,但我不確定如何在初始化順序中引入噪聲,以增加失敗的可能性,如果行為未定義的話。
通常,依賴基類和派生類的靜態初始化順序是不安全的。 無法保證A
的靜態初始化將在B
之前發生。 這就是靜態初始化順序fiasco的定義。
你可以在第一次使用的習語上使用這個構造 :
// 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();
更新:然而,說,博格丹在評論中指出
根據標准中的[3.6.2],保證了該特定示例中的初始化順序。 它與繼承無關,但事實上
A::count
的初始化是常量初始化 ,這保證在動態初始化之前完成,這是B::id
使用的。
但是除非你完全掌握這些內部空間,否則我建議你在第一次使用成語時使用這個結構 。
在這種情況下它是可以的,但要注意多線程上下文中的A::register_subclass
等函數。 如果多個線程同時調用它可能會發生任何事情
我想知道,如果在翻譯單元中“初始化順序未定義”的規則仍然適用於父類中的靜態成員,而子類中的靜態成員則需要這樣。
是的,它確實。
靜態數據成員與繼承層次結構(或者實際上,它們的封裝類完全相關)的唯一方式是它們的完全限定名稱; 他們的定義和初始化完全沒有意識到/不關心這一點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.