簡體   English   中英

類heirarchy中的靜態初始化順序

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM