2010-11-04 116 views
7

我知道你通常在.cpp文件中初始化一個靜態成員變量。但我的問題是:爲什麼你你爲什麼要初始化一個C++靜態成員變量?

下面是一個例子:

#include <vector> 

using namespace std; 

class A { 
    public: 
     static vector<int> x; 
}; 

main() { 
    int sz = A::x.size(); 
} 

這給出了一個編譯器錯誤:undefined reference to 'A::x'

然而,這樣的:

#include <vector> 

using namespace std; 

class A { 
    public: 
     static vector<int> x; 
}; 

// Initialize static member 
vector<int> A::x; 

main() { 
    int sz = A::x.size(); 
} 

編譯並運行良好。

我可以理解,如果我使用默認的構造函數以外的東西初始化矢量,但我不是。我只想創建一個大小爲0的矢量。當然,任何靜態成員都必須在程序初始化時分配內存,爲什麼編譯器不使用默認構造函數?

回答

14

這就是不是關於初始化,它是關於定義。 或者更確切地說:它是關於知道哪個編譯單元(的.cpp)將持有的對象(已被唯一某處定義)

那麼,什麼是需要的只不過是將定義某處,在一個獨特的地方,這是一個CPP,讓編譯器知道,當類的靜態對象被調用時,它被定義在那裏和其他地方。 (如果你試圖在頭文件中定義你的靜態文件,包含這個頭文件的每個cpp都會有一個定義,這使得不可能知道它應該在哪裏定義 - 如果需要使用,則手動初始化) 。

+2

+1,但你應該刪除其中一個dups。對於對象,RAII會進行初始化(即使只是默認的構造函數)也是定義的結果。這是否適用於原始指針,像int這樣的內建類型? – 2010-11-04 15:30:02

+0

我的意思是你可以在那裏添加初始化。我會添加精度。 – Klaim 2010-11-04 15:45:07

+0

@Steve POD類型的構造函數只是語法的,所以是的,它確實有效,但它實際上並沒有做任何事情(或者更準確地說,它被允許什麼也不做 - 通過C++標準)。 – 2010-11-04 19:06:16

2

你所說的初始化是定義。您需要在某處定義靜態成員。類內部分只是一個聲明。

這主要是因爲在頭文件中定義了一個定義會導致很大的問題(因爲您不能將該頭文件包含到多個翻譯單元中而不會導致多個定義)。

8

您正在從一個編譯單元的角度來看它。

但是,語言必須假設可能有多個編譯單元。那麼現在編譯單元是在哪個靜態對象中創建的呢?基本上編譯器不允許做出這個決定,工程師必須做出決定。

3

undefined reference to 'A::x'不是編譯器錯誤;這是一個鏈接器錯誤。這意味着在任何被鏈接在一起形成程序的翻譯單元中都找不到A::x的定義。靜態成員變量具有外部鏈接,並且必須在一個翻譯單元中定義。任何有外部鏈接的東西都不會有編譯器生成的定義,除非你編寫了一個定義。