我一直試圖了解靜態變數是如何初始化的。并注意到在cppref和enseignement中關于常數初始化和零初始化的順序的矛盾。
在cppref,它說:
恒定初始化是在靜態和執行緒本地(從C 11開始)物件的零初始化以及所有其他初始化之前進行的替代。
而在enseignement中則說:
恒定初始化是在靜態和執行緒本地物件的零初始化之后,在所有其他初始化之前進行的。
所以你可以看到cppref使用了 "instead",而第二個網站使用了 "after"。這兩者中哪一個是正確的?也就是說,零初始化總是先發生,然后如果可能的話,像第二個網站所暗示的那樣進行常量初始化,還是反過來。
那里給出的例子如下:
#include <iostream>
#include <array>
結構 S {
static const int c。
};
const int d = 10 * S::c; //不是一個常量表達。S::c沒有前綴。
///初始化器,這個初始化發生在 const之后。
const int S::c = 5; //常量初始化,保證先發生。
int main()
{
std::cout << "d =" << d << '
'。
std::array<int, S::c> a1; // OK: S::c是一個常量運算式。
// std::array<int, d> a2; // error: d不是一個常量運算式。
}
這是我目前對初始化程序的理解:
- 常量初始化,如果可能的話 。
- 只有在沒有進行恒定初始化的情況下才進行零初始化 。
- 動態初始化 。
現在根據上面的內容(我的理解),上面的代碼是這樣的:
步驟1.當控制流到達const int d的定義時,它看到初始化器有一個變數(即S::c)還沒有被初始化。所以陳述句const int d = 10 * S::c;是一個動態時間(運行時)初始化。這意味著它只能發生在靜態初始化之后。當然,d也不是一個常量運算式。
第2步。
控制流到達變數const int S::c;的定義。然而在這種情況下,初始化器是一個常量運算式,所以常量初始化可以發生。而且不需要進行零初始化。
第3步。
但是請注意,我們(編譯器)仍然沒有初始化變數d,因為它離開了初始化,因為它必須動態地完成。所以現在這將發生,d將得到值50。但是請注意d仍然不是一個常量運算式,因此我們不能在需要常量運算式的地方使用它。
我對這個概念的分析/理解是否正確,代碼的行為是否與描述的一樣?
注:
在cppref-init和enseignement-init,常數初始化和零初始化的順序也不同。
uj5u.com熱心網友回復:
當有疑問時,請求助于標準。由于這個問題被標記為C 11,我們將參考N3337.
變數的靜態存盤時間([basic.stc.static])或執行緒 存盤時間([basic.stc.thread])的變數應被零初始化。 ([dcl.init]) 在任何其他初始化發生之前。
持續初始化。
恒定的初始化被執行。[...]
零初始化和常量初始化一起被稱為 靜態初始化;所有其它的初始化都是動態的 初始化。靜態初始化應在任何動態初始化發生之前進行。
靜態初始化應在任何動態初始化發生之前進行。
因此,關于C 11標準,enseignement的描述是準確的。
恒定初始化是在靜態和執行緒本地物件的零初始化之后,在所有其他初始化之前進行的。
然而,根據CWG 2026,這被標記為缺陷:
CWG同意,在這些情況下,常量初始化應該被認為是發生了,而不是零初始化,這使得宣告不符合格式。
而從C 17(N4659)開始,這種情況被改變了,從此受[basic.start.static]/2的管轄:
[...] 如果一個具有靜態或執行緒存盤期限的變數或臨時物件被物體的常量初始化器初始化,則會執行常量初始化。如果不執行恒定初始化,那么具有靜態存盤期限或執行緒存盤期限的變數被零初始化。零初始化和恒定初始化一起被稱為靜態初始化;所有其他初始化是動態初始化。
但是,由于這不僅僅是新的標準功能的更新,而是一個缺陷,它向舊的標準進行了回溯,最終cppreference的描述對于C 11也是準確的(事實上一直到C 98),而enseignement的描述既沒有考慮到現代C 標準,也沒有考慮到DR CWG 2026。
我自己從未訪問過 enseignement 的頁面,但在快速瀏覽了他們的參考頁面之后,它看起來像是 cppreference 本身的一個非常舊的版本,要么完全沒有歸功于 cppreference,要么 cppreference 實際上是作為與 enseignement 作者的合作專案開始的。
除了標準本身,我認為cppreference是一個事實上的參考資料,考慮到enseignement的舊拷貝-pasta,我建議不要再轉向那些頁面參考。事實上,我們可以訪問關于常量初始化的實際最新的cppreference頁面,滾動到最下面,并閱讀: 以下改變行為的缺陷報告被應用于
追溯到之前發布的C 標準。
[...]
標籤:
缺陷報告
