[英]Does static initialization order fiasco apply to block-scope static variables?
[英]Is what constitutes a failed initialization of block-scope static or thread storage duration variables underspecified?
在回答了這個問題而沒有在標准文件中找到令人滿意的答案后,我開始疑惑。 該標准規定了以下wrt初始化提到的變量:
§6.7 [stmt.dcl] p4
[...]否則這個變量在第一次控制通過其聲明時被初始化; 這樣的變量在初始化完成后被認為是初始化的 。 如果通過拋出異常退出初始化,則初始化未完成,因此下次控制進入聲明時將再次嘗試初始化。
如果除了拋出異常( longjmp()
,thead exit,信號等等)之外的其他任何東西都失敗了,那就沒有提到可能導致初始化重試的原因。
我是否忽略了標准中的任何內容? 我一遍又一遍地查看初始化,聲明和異常條款,甚至通過快速搜索“靜態”來查詢CWG缺陷表 ,但找不到任何相關內容。
這是標准中的一個不明確的(並且作為這樣的缺陷)嗎?
C ++規范只能定義C ++規范中包含的內容。 請記住:C ++規范定義了它定義的虛擬機的行為。 如果它沒有定義某些事情可能發生,它肯定沒有定義C ++的行為圍繞着它沒有說的事情會發生。
根據C ++規范,線程可以通過三種方式退出:從其main函數返回,通過其main函數拋出異常,以及直接進程退出(與std::terminate
或類似函數一樣)。 簡而言之,C ++線程無法以任何其他方式退出。 標准C ++中沒有ExitThread
函數。 類似地, std::thread
無法在外部或內部殺死線程。
因此,根據定義,任何確實導致C ++所說不會發生的事情都是未定義的。 我想它甚至不會是“未定義的行為”; 在C ++ 11實際規定線程交互如何工作之前,線程就在那個模糊的空間中。
“信號”也是如此,無論那些是什么。 C ++規范並未說明那些會導致函數退出。 這里是龍。
至於longjmp
,那是longjmp
的行為所涵蓋的。 當你使用longjmp
退出函數時,該函數永遠不會完成,就像你使用了throw
和catch
。 在C ++中,只有在構造函數完成時才構造對象。 因此,對象的初始化從未完成,並且未初始化。
我沒有ISO C規范(C ++引用了longjmp
的行為),但是C ++ 11強烈建議你可以將throw
/ catch
等同於longjmp
/ setjmp
,只要你得到未定義的行為:
§18.10 [support.runtime] p4:
函數簽名longjmp(jmp_buf jbuf,int val)在本國際標准中具有更多限制行為。 如果用catch和throw替換setjmp和longjmp,則setjmp / longjmp調用對具有未定義的行為將為任何自動對象調用任何非平凡的析構函數。
所以我不認為這是不明確的。 它可能不是很好,整潔,但所有的部分都在那里。
僅僅因為案文提到一個特定的案例並不意味着遺漏其他人會有所不同。 如果還有其他方法可以阻止初始化完成,則實現必須在下次執行時重試。
我認為Nicol的答案大多是正確的,但是一個非平凡的構造函數並不意味着一個非平凡的析構函數。 因此, longjmp
可能會中斷初始化,因此必須重試它。 這僅在多線程環境中很棘手,在多線程環境中,需要使用互斥鎖來防止線程之間的爭用條件成為第一個執行初始化的線程。 幻像互斥對象需要一個非平凡的析構函數,即使初始化對象沒有。 可能的結果是死鎖。 這可能是DR的好材料。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.