談談C++中各種初始化方式
最近正在看《C++ Primer》第五版,已經被C++的各種初始化方式搞的頭昏腦脹,所以特寫此文,來總結一下C++的各種初始化的方式。
C++的初始化有很多方式:預設初始化,值初始化,直接初始化,拷貝初始化,列表初始化。這些方式之間有什麼區別與聯絡呢?我們一一來看。
1.預設初始化
預設初始化是指定義變數時沒有指定初值時進行的初始化操作。例如int a; Sales_data myData;等等。這些變數被定義了而不是僅僅被宣告(因為沒有extern關鍵字修飾),而且沒有顯式的賦予初值。特別的,如果採用動態分配記憶體的方式(即採用new關鍵字)建立的變數,不加括號時(如int *p=new int;)也是預設初始化,加了括號(如int *p=new int())為值初始化。變數的值與變數的型別與定義的位置有關係。
(1)對於內建型別變數(如int,double,bool等),如果定義在語句塊外(即{}外),則變數被預設初始化為0;如果定義在語句塊內(即{}內),變數將擁有未定義的值。
(2)對於類型別的變數(如string或其他自定義型別),不管定義於何處,都會執行預設建構函式。如果該類沒有預設建構函式,則會引發錯誤。因此,建議為每個類都定義一個預設建構函式(=default)。
2.值初始化
值初始化是值使用了初始化器(即使用了圓括號或花括號)但卻沒有提供初始值的情況。例如,int *p=new int();vector<string> vec(10);等等都是典型的值初始化方式。注意,當不採用動態分配記憶體的方式(即不採用new運算子)時,寫成int a();是錯誤的值初始化方式,因為這種方式聲明瞭一個函式而不是進行值初始化
3.直接初始化與拷貝初始化
直接初始化與拷貝初始化對應,其內部實現機理不同。直接初始化是指採用小括號的方式進行變數初始化(小括號裡一定要有初始值,如果沒提供初始值,那就是值初始化了!)。例如int a(12);Sales_data myData(para);vector<int> ivec(ivec2);string s("123456");等等。拷貝初始化是指採用等號(=)進行初始化的方式。例如int a=12;string s=string("123456");等等。拷貝初始化看起來像是給變數賦值,實際上是執行了初始化操作,與先定義再賦值本質不同。
(1)對於內建型別變數(如int,double,bool等),直接初始化與拷貝初始化差別可以忽略不計。
(2)對於類型別的變數(如string或其他自定義型別),直接初始化呼叫類的建構函式(呼叫引數型別最佳匹配的那個),拷貝初始化呼叫類的拷貝建構函式。
特別的,當對類型別變數進行初始化時,如果類的建構函式採用了explicit修飾而且需要隱式型別轉換時,則只能通過直接初始化而不能通過拷貝初始化進行操作。
4.列表初始化
列表初始化是C++ 11 新引進的初始化方式,它採用一對花括號(即{})進行初始化操作。能用直接初始化和拷貝初始化的地方都能用列表初始化,而且列表初始化能對容器進行方便的初始化,因此在新的C++標準中,推薦使用列表初始化的方式進行初始化。列表初始化的應用場景有:int a{12};string s{"123"};vector<int> vec{1,2,3};這裡一定要注意,列表初始化使用的是花括號而不是圓括號!