3 回答

TA貢獻(xiàn)1811條經(jīng)驗(yàn) 獲得超6個(gè)贊
前段時(shí)間在usenet上對(duì)此進(jìn)行了討論,而當(dāng)時(shí)我正試圖回答關(guān)于stackoverflow的另一個(gè)問(wèn)題:靜態(tài)數(shù)據(jù)成員的實(shí)例化點(diǎn)。我認(rèn)為減少測(cè)試用例,并單獨(dú)考慮每種情況是值得的,所以讓我們首先更一般地看一下它:
struct C { C(int n) { printf("%d\n", n); } };
template<int N>
struct A {
static C c;
};
template<int N>
C A<N>::c(N);
A<1> a; // implicit instantiation of A<1> and 2
A<2> b;
您已定義了靜態(tài)數(shù)據(jù)成員模板。由于以下原因,此操作尚未創(chuàng)建任何數(shù)據(jù)成員14.7.1:
“ ...尤其是,除非以某種方式要求使用靜態(tài)數(shù)據(jù)成員的定義才能使用靜態(tài)數(shù)據(jù)成員,否則不會(huì)發(fā)生靜態(tài)數(shù)據(jù)成員的初始化(以及任何相關(guān)的副作用)?!?/p>
根據(jù)定義該詞的一種定義規(guī)則(在處3.2/2),當(dāng)“使用”某個(gè)實(shí)體時(shí),需要定義某種事物(=實(shí)體)。特別是,如果所有引用均來(lái)自未實(shí)例化的模板,模板的成員或sizeof表達(dá)式或不“使用”實(shí)體的類(lèi)似事物(因?yàn)樗鼈兛赡軟](méi)有對(duì)實(shí)體進(jìn)行評(píng)估,或者它們還不作為函數(shù)存在) / member函數(shù)本身),則不會(huì)實(shí)例化此類(lèi)靜態(tài)數(shù)據(jù)成員。
隱式實(shí)例化通過(guò)14.7.1/7實(shí)例化靜態(tài)數(shù)據(jù)成員的聲明-也就是說(shuō),它將實(shí)例化處理該聲明所需的任何模板。但是,它不會(huì)實(shí)例化定義-也就是說(shuō),不會(huì)實(shí)例化初始化程序,并且不會(huì)隱式定義該靜態(tài)數(shù)據(jù)成員類(lèi)型的構(gòu)造函數(shù)(標(biāo)記為已使用)。
這一切都意味著,以上代碼將不會(huì)輸出任何內(nèi)容?,F(xiàn)在讓我們引起靜態(tài)數(shù)據(jù)成員的隱式實(shí)例化。
int main() {
A<1>::c; // reference them
A<2>::c;
}
這將導(dǎo)致兩個(gè)靜態(tài)數(shù)據(jù)成員存在,但問(wèn)題是-初始化的順序如何?簡(jiǎn)單閱讀一下,可能會(huì)認(rèn)為這3.6.2/1適用,(我強(qiáng)調(diào)):
“具有在同一翻譯單元中的名稱空間范圍內(nèi)定義并動(dòng)態(tài)初始化的具有靜態(tài)存儲(chǔ)持續(xù)時(shí)間的對(duì)象,應(yīng)按照其定義在翻譯單元中出現(xiàn)的順序進(jìn)行初始化?!?/p>
現(xiàn)在,如usenet帖子中所述,并在此缺陷報(bào)告中進(jìn)行了說(shuō)明,這些靜態(tài)數(shù)據(jù)成員未在轉(zhuǎn)換單元中定義,但是在實(shí)例化單元中實(shí)例化,如以下所述2.1/1:
檢查每個(gè)翻譯的翻譯單元,以產(chǎn)生所需實(shí)例的列表。[注意:這可能包括已明確請(qǐng)求的實(shí)例化(14.7.2)。]找到了所需模板的定義。由實(shí)現(xiàn)定義,是否要求包含這些定義的翻譯單元的源是否可用。[注意:一個(gè)實(shí)現(xiàn)可以將足夠的信息編碼到翻譯的翻譯單元中,以確保此處不需要源。]執(zhí)行所有必需的實(shí)例化以生成實(shí)例化單元。[注意:它們類(lèi)似于翻譯后的翻譯單元,但不包含對(duì)未實(shí)例化模板的引用,也沒(méi)有模板定義。]如果任何實(shí)例化失敗,則程序格式錯(cuò)誤。
這樣的成員的實(shí)例化點(diǎn)也并不重要,因?yàn)檫@樣的實(shí)例化點(diǎn)是實(shí)例化及其轉(zhuǎn)換單元之間的上下文鏈接-它定義了可見(jiàn)的聲明(如處所指定14.6.4.1,以及的每個(gè)點(diǎn))實(shí)例化必須賦予實(shí)例化相同的含義,如3.2/5最后一個(gè)項(xiàng)目符號(hào)的一個(gè)定義規(guī)則中所指定)。
如果我們要進(jìn)行有序的初始化,則必須進(jìn)行安排,以免混淆實(shí)例化,而是使用顯式聲明-這是顯式專(zhuān)業(yè)化的領(lǐng)域,因?yàn)樗鼈兣c普通聲明沒(méi)有真正的不同。實(shí)際上,C ++ 0x將其措辭更改3.6.2為以下內(nèi)容:
具有靜態(tài)存儲(chǔ)持續(xù)時(shí)間的非本地對(duì)象的動(dòng)態(tài)初始化是有序的或無(wú)序的。顯式專(zhuān)門(mén)化的類(lèi)模板靜態(tài)數(shù)據(jù)成員的定義已進(jìn)行了初始化。其他類(lèi)模板靜態(tài)數(shù)據(jù)成員(即,隱式或顯式實(shí)例化的專(zhuān)長(zhǎng))具有無(wú)序初始化。
這對(duì)您的代碼意味著:
[1]并[2]評(píng)論:不存在對(duì)靜態(tài)數(shù)據(jù)成員的引用,因此B<int>不會(huì)實(shí)例化它們的定義(并且也不需要聲明,因?yàn)椴恍枰獙?shí)例化)。沒(méi)有副作用發(fā)生。
[1]uncommented:B<int>::getB()被使用,其本身使用B<int>::mB,這要求該靜態(tài)成員存在。字符串在main之前初始化(無(wú)論如何,在該語(yǔ)句之前,作為初始化非本地對(duì)象的一部分)。什么都沒(méi)有使用B<int>::mInit,所以它不會(huì)被實(shí)例化,因此B<int>::InitHelper也不會(huì)創(chuàng)建任何對(duì)象,這使得它的構(gòu)造函數(shù)沒(méi)有被使用,這反過(guò)來(lái)將永遠(yuǎn)不會(huì)給分配任何東西B<int>::mB:您只會(huì)輸出一個(gè)空字符串。
[1]并[2]取消注釋?zhuān)罕竟ぷ鲗?duì)你來(lái)說(shuō)是運(yùn)氣(或者相反:))。如上所述,不需要特定順序的初始化調(diào)用。它可能在VC ++上運(yùn)行,在GCC上失敗,在clang上運(yùn)行。我們不知道
[1]評(píng)論說(shuō),[2]取消注釋?zhuān)和瑯拥膯?wèn)題-再次,這兩個(gè)靜態(tài)數(shù)據(jù)成員的使用:B<int>::mInit使用的B<int>::getHelper,和的實(shí)例B<int>::mInit被實(shí)例化會(huì)導(dǎo)致它的構(gòu)造函數(shù),將使用B<int>::mB-但你的編譯器,順序是在這個(gè)特殊的運(yùn)行不同(未指定的行為不需要在不同的運(yùn)行之間保持一致):首先進(jìn)行初始化B<int>::mInit,該操作將在尚未構(gòu)造的字符串對(duì)象上進(jìn)行。

TA貢獻(xiàn)1895條經(jīng)驗(yàn) 獲得超3個(gè)贊
[1]未注釋的情況:可以。
static InitHelper B<int>::mInit
不存在。如果不使用模板類(lèi)(struct)的成員,則不會(huì)編譯。[1]和[2]未注釋的情況:可以。
B<int>::getHelper()
使用static InitHelper B<int>::mInit
和mInit
存在。[1]評(píng)論,[2]未評(píng)論:它在VS2008中對(duì)我有用。
- 3 回答
- 0 關(guān)注
- 417 瀏覽
添加回答
舉報(bào)