C++中static變量的初始化

作者:billy
版權聲明:著作權歸作者所有,商業轉載請聯繫作者獲得授權,非商業轉載請註明出處

前言

在C語言中,static變量如果初始化,那麼初始化發生在任何代碼執行之前,屬於編譯期初始化。全局變量、static全局變量、static局部變量,此三者的生命週期、初始化方法完全一致,只是可見範圍不同。

而在C++中我們引入了對象,這給全局變量的管理帶領新的麻煩。C++的對象必須由構造函數生成,並最終執行析構操作。由於構造和析構並非分配內存那麼簡單,可以說相當複雜,因此何時執行全局或靜態對象的構造和析構呢?這需要執行相關代碼,無法在編譯期完成。因此不同的static變量,在不同的時間被初始化,我們需要分情況來討論。

編譯時初始化

如果靜態變量本身是基本數據類型(POD),且初始化值是常量,那麼這個初始化過程是在編譯期間完成的。

static int val = 10;
static char strArray[] = "hello world !";

加載時初始化

程序被加載時立即進行的初始化。這個初始化發生在main函數之前。即使程序任何地方都沒訪問過該變量, 仍然會進行初始化,因此形象地稱之爲"餓漢式初始化"。

  1. 靜態變量是一個基本數據類型,但是初始值非常量
static int *p = new int[1024];

int x = 3;
int y = 4;
static int z = x + y;
  1. 靜態變量是一個類對象,這種情況下即使是使用常量初始化,也是加載時初始化,而不是編譯時初始化
static std::string str = "Hello world !";

class MyClass {
public:	
	MyClass();    
	MyClass(int a, int b)
;};

static MyClass* MyClass1 = new MyClass();
static MyClass MyClass2;

運行時初始化

這個初始化發生在變量第一次被引用
也就是說,從程序執行模型角度看,程序所在進程空間中,哪個線程先訪問了這個變量,就是哪個線程來初始化這個變量。因此,相對於加載初始化來說,這種初始化是把真正的初始化動作推遲到第一次被訪問時,因而形象地稱爲"懶漢式初始化"。

int myfunc()
{     	
    static std::string msg = "hello world !";    //運行時初始化
}

static 初始化的原理

例1:
int main()
{
    for(int x = 5; x < 10; x++)
    {
        static int y = x;	//第一次被引用時初始化,並且只初始化一次
        cout << "x = " << x << ", y = " << y << endl;
    }
    return 0;
}

輸出結果:
x = 5, y = 5
x = 6, y = 5
x = 7, y = 5
x = 8, y = 5
x = 9, y = 5
例2:
int main()
{
    for(int x = 5; x < 10; x++)
    {
        static int y = x;
        cout << "x = " << x << ", y = " << y << endl;

        int *p = &y;
        p++;
        *p = 0;
    }
    return 0;
}

輸出結果:
x = 5, y = 5
x = 6, y = 6
x = 7, y = 7
x = 8, y = 8
x = 9, y = 9

通過兩個例子的結果我們可以知道,靜態變量的初始化就是通過靜態變量後面的一個32位內存位來做記錄,以標識這個靜態變量是否已經初始化。每次運行到當前位置,會先去判斷這個地址:
如果不是1,就給它賦值1,然後給變量賦值;
如果是1,直接跳過賦值代碼塊這樣它就做到了只賦值一次的效果;

在例2中我們每次都將這個值賦值爲0,所以程序就一直認爲變量一直沒有被初始化過,並每次都初始化。該操作並非一個原子操作,因此從代碼邏輯角度來說,static變量並不具有“線程安全”性能。

總結

  1. 如果是編譯時和加載時初始化,是不會存在線程安全這個問題的。因爲這兩種初始化一定發生在Main函數執行之前,這個時候尚未進入程序運行空間,而這些初始化一定是在單線程環境下操作的。
  2. 如果是運行時初始化,因爲無法保證訪問這個靜態變量一定只會從某個特定的線程中被訪問,因此會存在"線程安全"的問題。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章