1. 程式人生 > >c++初始化 未賦值部分

c++初始化 未賦值部分

陣列初始化列表中的元素個數小於指定的陣列長度時,不足的元素補以預設值。

對於基本型別int來說,當然就是補int()即0了。再看一下非基本型別的陣列:

string a[5] = { "foo" };

有了上面的規則,就很容易知道其實相當於:

string a[5] = { "foo", "", "", "", "" };

即後面4個元素呼叫了string的預設建構函式進行的初始化,而第一個則呼叫的string::string(const char*)進行的初始化。

還有一個區別:

  1. int a[5];

  2. string a[5];

如果不明確指出初始化列表,那麼基本型別是不會被初始化的(除全域性變數和靜態變數外),所有的記憶體都是“髒的”;而類型別則會為每個元素呼叫預設建構函式進行初始化。

注意,在C++11中中間的賦值號可以省略,即 int a[5]{1}; 並且,如果初始化列表為空,如 int a[5]{},那將初始化所有元素為預設值,即與 int a[5]{0}; 等價

動態陣列的初始化

說完了棧中的陣列的初始化,我發現new一個數組和其又有一些不同:

  1. int* a = new int[5];

  2. string* a = new string[5];

  3. int* a = new int[5] { 0 };

  4. string* a = new string[5] { "foo" };

上面幾行程式碼遵循棧中陣列的初始化規則,除此之外這裡還有一個新語法:

int* a = new int[5]();

注意後面的一對圓括號,它的意思是使用預設值初始化整個陣列,所以對於類型別來說,new string[5] 與 new string[5]()是等價的,都會呼叫預設建構函式進行初始化;但是對於基本型別就不同了,new int[5]根本不會初始化,而new int[5]() 則會使用int()的值即0進行初始化。

看到這對圓括號,我想它該不會是元素的建構函式的引數列表吧,那麼我可能會想將陣列全部初始化為1:new int[5](1); 看起來很合理,但其實不行。事實上這對圓括號不是陣列元素的構造引數,可能是整個陣列的,它有三個過載版本:

看起來像是常引用、右值引用、和預設版本。所以假如已經有一個相同大小的陣列b,試著用b來初始化a:

int* a = new int[5](b);

結果編譯出錯,提示error C3074: an array cannot be initialized with a parenthesized initializer,看來這個括號的作用和我想的不一樣,其實也應該看出來的,要是是用另一個數組初始化的話那麼引數應該是const int (&)[5] 而不是 const int [5] &,而且後者好像是一個錯誤的型別。這個問題暫時無解。

錯過了初始化時機(memset的誤區)

如果想在陣列建立結束後再對其進行初始化,可以使用C函式memset(),但是memset的使用有個大問題,就是它只對char型別的陣列管用:

  1. char a[10];

  2. memset(a, 1, 10); // 將每個元素設定為1

如果將上面的a陣列換成int或其他型別的,就會出現問題,因為memset的內部實現是以位元組為單位進行賦值的,int 型別大於一個位元組(假設是4個),陣列記憶體連續,如果有下面程式碼:

  1. int a[10];

  2. memset(a, 1, sizeof(a));

將只會對前sizeof(a)即40個位元組進行賦值1的操作,即給“前5個int”進行了賦值0x01010101的操作,失之毫厘謬以千里!

如果實在想再初始化,那麼老老實實迴圈賦值吧。