值初始化和默認初始化的適用場景:
值初始化:
(1)在數組初始化的過程中,如果提供的初始值數量少於數組的大小,剩下的元素會進行值初始化;
(2)靜態static變量、定義在塊作用域外的全局變量,如果沒有顯式的初始值,將執行值初始化;
(3)當我們通過書寫形如T()的表達式(例如 int())顯式地請求值初始化時;
默認初始化:
(1)當我們在塊作用域內(類內也屬於塊作用域內)不使用任何初始值定義一個非靜態變量時;
(2)當一個類本身含有類類型成員且使用合成的默認構造函數時;
(3)當類類型的成員沒有在構造函數初始值列表中顯式地初始化時;
一、相關概念:
聲明:在環境/上下文中指定一個變量的名字。也就是說,聲明僅僅是讓編譯器知道,而沒有實際分配空間。
初始化:給一個聲明后尚未初始化的變量一個有意義的初始值。
賦值 : 銷毀一個變量原來的值,並賦予一個新值。相當於改變了一個變量的狀態
二、初始化是在聲明一個變量的同時賦予它一個值,而賦值是已經聲明過了變量,后續再對它進行賦值操作。對於內置類型:
//在一個塊作用域內 { int i; //默認初始化,其值未定義 int j=0; //值初始化 j=1; //賦值 }
三、對於定義了自己的構造函數的類類型(例如string)來說,不管采用默認初始化還是值初始化,對象都會通過默認構造函數來初始化。
但對於內置類型,值初始化的內置類型對象有着良好定義的值,而默認初始化的對象的值則是未定義的。
對於類中那些依賴於編譯器合成的默認構造函數的內置類型成員,如果他們未在類內被初始化,那么它們的值也是未定義的。
1 string *ps1 = new string; //默認初始化為空string 2 string *ps2 = new string(); //值初始化為空string 3 int *pi1 = new int; //默認初始化;*pi1的值未定義 4 int *pi2 = new int(); //值初始化為0;*pi2為0 5 6 7 class X 8 { 9 int a; 10 public: 11 void ShowX() 12 { 13 cout << a ; 14 } 15 X() = default; 16 }; 17 int main() 18 { 19 X xx; 20 xx.ShowX(); //對象xx中的a成員的值被默認初始化,由於a是在塊作用域內定義的,所以此處輸出的值未定義 21 22 return 0; 23 }
四、定義於塊作用域內(類內也屬於塊作用域內)的內置類型變量將不被初始化,其值未定義;定義於塊作用域外的全局變量被值初始化為0。
靜態static變量如果沒有顯式的初始值,它將執行值初始化。
1 class X 2 { 3 int a; 4 public: 5 void ShowX(){cout << a ;} 6 X() = default; 7 }; 8 int main() 9 { 10 X xx; 11 xx.ShowX(); //對象xx中的a成員的值被默認初始化,由於a是在塊作用域內定義的,所以此處輸出的值未定義 12 13 return 0; 14 }
五、對於自定義類型和STL中的容器,
class A;
A a=A();//值初始化
std::vector<int> vec1;//默認初始化,調用默認構造函數
一個類對象進行默認初始化和值初始化,必須要有相應的默認構造函數。否則將會報錯,因為無法構造這個類。