[英]Static-storage-duration initialization
在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();
}
但是,問題在於,對於標准庫所需的所有初始化,在哪里可以保證做到這一點。
我不確定標准(*)中是否明確聲明了它,但是通常std :: cin , std :: cout和std :: cerr是在Nifty Counter習慣用法的幫助下實現的。
基本思想是在頭文件中包含一個輔助靜態對象,該對象在初始化期間檢查流對象是否已被初始化,如果沒有,則對其進行初始化。 通常首先包括這樣的內容,即在相同轉換單元中的任何其他靜態對象之前初始化此類輔助靜態對象,並確保在任何其他靜態對象可以引用它之前對流對象進行適當的初始化。
(*) 編輯:
這是標准草案N3936中的適當措詞:
27.4標准iostream對象
27.4.1.2
在構造ios_base :: Init類的對象之前或第一次期間的某個時間,並且無論如何在main主體開始執行之前或之前的某個時間,構造對象並建立關聯。 程序執行期間不會破壞對象。 在轉換單元中包含<iostream>的結果應類似於定義了具有靜態存儲持續時間的ios_base :: Init實例。 同樣,整個程序的行為就好像至少有一個ios_base :: Init實例具有靜態存儲持續時間一樣。
TL;博士; 在foo_instance
初始化期間,不應使用std::cout
。
無論標准中標准流的初始化如何,唯一的要求是
27.4.1概述[iostream.objects.overview]
3在構造
ios_base::Init
類的對象之前或第一次期間的某個時間,以及無論如何在main主體開始執行之前的某個時間,都將構造對象並建立關聯。 291在程序執行過程中未破壞對象。 292在轉換單元中包含<iostream>
的結果應類似於<iostream>
定義了具有靜態存儲持續時間的ios_base::Init
實例。
因此,如果在聲明靜態變量之前包含<iostream>
,則可以保存,因為根據標准
3.6.3非局部變量的動態初始化[basic.start.dynamic]
2具有靜態存儲持續時間的非局部變量V和W的動態初始化的順序如下:(2.1)如果V和W進行了順序初始化,並且V在單個轉換單元中的W之前定義,則V的初始化在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;
}
因此,我可以得出結論,在非局部變量的動態初始化期間不能使用std :: cout。
看一下標題<iostream>
。
該標准說,它的行為就像定義了一個std::ios_base::Init
類型的TU本地對象一樣,該對象處理初始化並最終沖洗標准流。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.