2017-02-22 126 views
5

關於來自Scot Meyers的書籍「Effective C++」,以及第4項:非本地靜態對象可以在使用之前未初始化(在本例中靜態意味着「全局「,靜態的生活)。如果將其替換爲在返回對其引用的函數內部創建的local-static對象,則該對象在使用前確定已初始化。C++ - 非本地靜態對象vs本地靜態對象

我總是有一個帶有常量的文件。我在.hpp文件中聲明extern const int a;並在.cpp文件中定義它。但是,那麼同樣的事情會發生嗎? a可以是未初始化的。或不?相同的規則是否適用於內置類型?

+4

全局範圍內的變量*始終*初始化。即使它們在定義時沒有明確的初始化,系統也會[*初始化*](http://en.cppreference.com/w/cpp/language/zero_initialization)。無論如何,'const'變量必須被明確地初始化。 –

+0

你可能想看看http://stackoverflow.com/questions/1005685/c-static-initialization-order –

+0

嘿傢伙,謝謝你!據我所見,初始化內置類型的全局對象總是由編譯器處理,不必介意它們是本地還是非本地... – Dusan

回答

2

儘管可以,但返回對「local-static」變量的引用並不是一個好主意。這個變量(大概)是在本地聲明的,以便將它的範圍縮小到封閉函數,所以試圖以這種方式增加它的範圍是相當黑的。你可以使它成爲一個全局變量,並使用類似std::call_once的內容來保證它在第一次使用時僅被初始化一次。將可變引用返回給本地靜態對象也會引發線程安全問題,因爲該函數可能不再可重入。

具有靜態存儲時間的POD類型保證被零初始化。你也可以用一個常量表達式來初始化它們,並且這個語言將保證它們在動態初始化發生之前被初始化。這裏的a similar question可能會提供一些額外的見解。

0

關於靜態初始化被稱爲static initialization order fiasco問題:

總之,假設您有兩個靜態對象x和y存在於 不同的源文件,說x.cpp和y.cpp的。進一步假設y對象的初始化(通常是y對象的構造函數) 在x對象上調用某種方法。

所以,如果你有另一個使用你的常量的翻譯單元,你有一個很好的機會,你的程序將無法正常工作。有時它是文件鏈接在一起的順序,有些平臺甚至在文檔中定義它(我認爲Solaris是這裏的一個例子)。

The problem also applies to builtin types such as int.從常見問題中的例子是:

#include <iostream> 
int f(); // forward declaration 
int g(); // forward declaration 
int x = f(); 
int y = g(); 
int f() 
{ 
    std::cout << "using 'y' (which is " << y << ")\n"; 
    return 3*y + 7; 
} 
int g() 
{ 
    std::cout << "initializing 'y'\n"; 
    return 5; 
} 

int main() { 
    std::cout << x << std::endl << y << std::endl; 
    return 0; 
} 

如果運行該例子中,輸出是:

使用 'Y'(其爲0) 初始化 'Y'

因此,y首先得到零初始化,然後發生常量初始化(?)。

的解決方案是 Construct On First Use Idiom

的構建在第一次使用成語的基本思想是包裝一個函數內部 靜態對象。

靜態位置對象是在控制流首次到達其聲明時構建的。