2014-02-13 68 views
0

下面是用關鍵字static聲明兩個變量:C++:靜態成員不能在聲明中定義,但靜態函數變量可以?

void fcn() { 
    static int x = 2; 
} 

class cls() { 
    static int y; 
}; 

我們都知道,爲了cls正確鏈接,int cls::y需要由程序員明確定義一次。

基於答案static variables in an inlined function,似乎即使需要fcn::x外的類的定義,可以保證從不同的編譯單元的fcn甚至內嵌版本將引用同一個fcn::x。如果這是真的,那麼鏈接器必須足夠聰明才能在編譯單元之間到達並連接「同一個」變量的多個實例,以確保靜態函數變量按預期執行。

如果這是可能的靜態函數變量,在我看來,它也應該是可能的靜態類成員...那麼,爲什麼不標準需要靜態類成員的單外的類定義?

回答

0

是,連接器將確實有合併的fcn::x不同實例。換句話說,即使正式的語言說,fcn::x沒有聯繫,身體就不得不暴露在包含它的所有目標文件的外部符號。這是通常在實踐中實現的方式:編譯器會將fcx::x公開爲某種嚴重受損的外部名稱@#$%^&_fcx_x或其他類型(以確保它永遠不會與「真正的」外部名稱衝突)。這是鏈接器將用於將fcn::x的所有實例合併成一個實例的內容。

至於類會員...首先,它是不是真的什麼是「可能的」。它是關於聲明和定義的語言級概念。它是關於一個定義規則,它是基於原始鏈接器特徵的「可能」更高級別的概念。根據該規則,具有外部連接的物體應由用戶定義,並且應具有且僅有一個定義。類的靜態數據成員是具有外部鏈接的對象。其餘的如下。

其次,和更實際的,有靜態數據成員的另一個嚴重的問題。這是它們的初始化順序。靜態數據成員[確保在不遲於來自包含翻譯單元的第一個函數被調用(其指代包含數據成員定義的翻譯單元)]時被初始化。在單個翻譯單元中聲明的靜態對象按其定義的順序進行初始化,從上到下。這是靜態數據成員初始化過程的一個重要屬性。允許靜態數據成員被「自動」定義會違反規範的這一部分,並且需要對這部分語言進行大規模的修改。

換句話說,當你爲類的靜態數據成員專用的定義,你不只是做它的ODR合規,實際上表達了該對象所需的初始化順序。

同時,函數內部的靜態變量是沒有鏈接的對象。因此,他們在概念層面接受不同的待遇。它們具有定義明確的初始化語義,完全不受需要將多個定義合併爲一個的影響。