2017-06-18 69 views
2

在C++中,靜態存儲持續時間對象以未指定的順序初始化(除了在同一個編譯單元中)。靜態存儲持續時間初始化

有了這樣的代碼:

#include <iostream> 

struct Foo { 
    Foo() { 
     std::cout << "Hello, world.\n"; 
    } 
} foo_instance; 

int main(int argc, const char *argv[]) { 
    return 0; 
} 

凡在我的foo_instance初始化過程中已經使用std::cout標準的陳述?

我知道我能保證事情會加入一些掛羊頭賣狗肉的<iostream>工作,例如通過具有含類似

int __ensure_stdout_initialization_call(); 
namespace { 
    int __ensure_stdout_initialization 
     = __ensure_stdout_initialization_call(); 
} 

但問題是關於在那裏的保證,這是對所有需要的初始化完成它由標準庫。

回答

2

tl; dr;在foo_instance的初始化期間,您不應該使用std::cout

唯一的要求不管在標準標準流的初始化是

27.4.1概述iostream.objects.overview]

3所述的對象構造和關聯被建立在一段時間之前在第一次或第一次構造類ios_base::Init的對象時,並且在任何情況下在主體開始執行之前。程序執行期間,對象不會被銷燬。 292在翻譯單元中包含<iostream>的結果應該如同<iostream>定義了具有靜態存儲持續時間的ios_base::Init的實例。

所以,如果你聲明你的靜態變量之前包括<iostream>你是保存,因爲根據標準

3.6.3非本地變量[basic.start.dynamic]

的動態初始化2具有靜態存儲持續時間的非局部變量V和W的動態初始化的排序如下: (2.1)如果V和W具有有序初始化且V在單個翻譯單元內的W之前定義,則V的初始化在W的初始化

所以ios_base::Init將您的變量前初始化和標準流將準備,但似乎你仍然可以打出自己的腿,如果你申報的包括<iostream>變量

struct Foo 
{ 
    Foo(); 
} foo_instance; // uses ::std::cout 

#include <iostream> // declares ios_base::Init variable that will init ::std::cout 

Foo::Foo() 
{ 
    std::cout << "Hello, world.\n"; 
} 

int main(int argc, const char *argv[]) { 
    return 0; 
} 

dying example

所以我可以斷定你不能在動態初始化非局部變量時使用std :: cout。

+0

好點。改變了接受的答案,因爲仍然提供參考顯示了一個漏洞。 – 6502

2

我不知道它是否在標準(*)明確規定,但通常給std :: cin的std ::法院的std :: CERRNifty Counter成語的幫助下實現的。

基本思想是在頭文件中包含一個輔助靜態對象,它在初始化時檢查流對象是否已經被初始化,如果否,則初始化它。由於通常包含在內,這樣的輔助靜態對象在相同翻譯單元中的任何其他靜態對象之前被初始化,並且在任何其他靜態對象可能引用它之前確保正確初始化流對象。

(*)編輯:

這裏是從標準草案適當的措詞N3936

27.4標準iostream對象

27.4.1.2

的構建對象並且在 s處建立關聯ome時間在第一次之前或期間,類 ios_base :: Init的對象被構​​造,並且在主體 的主體開始執行之前的任何情況下。在執行程序 時,對象不會被破壞。在翻譯單元 中包含< iostream>的結果應該如同定義了具有 靜態存儲持續時間的ios_base :: Init的實例。同樣,如果存在至少一個具有靜態 存儲持續時間的ios_base :: Init實例,則整個程序的行爲應該爲 。