C++11中列表初始化機制的概念與實例詳解
概述
定義:列表初始化是C++11引入的新標(biāo)準(zhǔn),目的是統(tǒng)一初始化方式
C++11以前只能使用列表初始化來初始化內(nèi)置類型數(shù)組和POD類型對象,C++11中列表初始化可以用于初始化任何類型對象
- POD(plain old data)類型:僅由內(nèi)置類型變量構(gòu)成且不含指針的類,簡單來說是可以直接使用memcpy復(fù)制的對象
- 聚合體(aggregate):聚合體一定是POD類型
- 無自定義構(gòu)造函數(shù)
- 無私有或保護(hù)的非靜態(tài)數(shù)據(jù)成員(靜態(tài)成員與單獨對象無關(guān),故不影響初始化)
- 無基類
- 無虛函數(shù)
- 無類內(nèi)已經(jīng)初始化的非靜態(tài)數(shù)據(jù)成員
注意:區(qū)分列表初始化和初始化列表
列表初始化:用{}進(jìn)行初始化的方式
初始化列表:構(gòu)造函數(shù)體前對對象成員直接進(jìn)行初始化的列表
initializer_list:一種用于未定參數(shù)的輕量STL容器
實現(xiàn)機制詳解
對內(nèi)置類型對象、POD對象和類對象的列表初始化實現(xiàn)細(xì)節(jié)是不同的
POD類型的列表初始化
- 此處POD類型包括:內(nèi)置類型、聚合體類
- 內(nèi)置類型數(shù)組按照順序初始化
- C++11標(biāo)準(zhǔn)中列表初始化會防止可能導(dǎo)致潛在信息丟失的類型縮小(即不能像賦值一樣將大類型如int隱式轉(zhuǎn)換成小類型如char)
- 聚合體類按照成員定義順序依次初始化
含有構(gòu)造函數(shù)的類的列表初始化(C++11)
- 通過{}進(jìn)行初始化和()結(jié)果一致【即通過()調(diào)用構(gòu)造函數(shù)的地方都可以完全等價地用{}代替】,都是直接用括號內(nèi)的值調(diào)用對應(yīng)構(gòu)造函數(shù)直接初始化對象,并不會先生成臨時對象再拷貝
- ={}與{}是等價的語法【即加不加=對初始化行為沒有影響】,均不會調(diào)用拷貝運算符或拷貝構(gòu)造函數(shù)
- 與內(nèi)置類型的列表初始化一致,C++11的列表初始化只能用于初始化,不能用于已初始化對象的賦值
- 實際機制猜想:傳遞的實際參數(shù)為initializer_list類型,通過匹配重載函數(shù)實現(xiàn)調(diào)用【我不知道怎么驗證這個過程,求大佬解答】
列表初始化用于函數(shù)返回值
- 在返回值類型為對象(不能是對象的引用)的函數(shù)中可以返回{}的列表初始化
- {}返回值的實際類型為initiallizer list(但不能聲明為std::initializer_list),相當(dāng)于返回構(gòu)造函數(shù)的表達(dá)式,因此類型不能是對象的引用
引入std::initializer_list
- initializer_list為一個輕量級STL模板,聲明在頭文件<initializer_list>中,定義在命名空間std中
- 任意的STL容器都與未指定長度的數(shù)組有一樣的初始化能力,可以填入任何數(shù)量的同類型數(shù)據(jù),因此可以用STL容器輕易對固定類型的類進(jìn)行賦值
- initializer_list是一個輕量級的模板,可以接受任意長度的同類型的數(shù)據(jù)也就是接受可變長參數(shù),同時作為STL容器它具有STL容器的共同特征(如迭代器)
- 只有三個成員接口:begin() end() size()
- 只能被整體的初始化和賦值,迭代器遍歷的數(shù)據(jù)僅可讀,不能對單個數(shù)據(jù)進(jìn)行修改
- 所有{}對象都是隱式創(chuàng)建的std::initializer_list類型字面量(右值),廣泛用于實現(xiàn)列表初始化(不需要頭文件)
代碼驗證
class testClass { private: int a; int b; public: testClass() :a(0), b(0) { cout << "default init\n"; } testClass(int a) :a(a), b(a) { cout << "sing-val init\n"; } testClass(int a, int b) :a(a), b(b) { cout << "val init\n"; } testClass(testClass& temp) :a(temp.a), b(temp.b) { cout << "copy init\n"; } testClass& operator=(testClass& temp) { //testClass& newobj = *this; a = temp.a; b = temp.b; cout << "copy assign\n"; return *this; } testClass& operator=(int x) { a = x; b = x; cout << "int-convert assign\n"; //testClass& newobj = *this; return *this; } testClass& operator++() { a++; b++; } void printVal(ostream& os) { os << "a=" << a << "\n"; os << "b=" << b << "\n"; } }; using tc = testClass; tc& makeObj(int x, int y) { return { x,y }; } int main() { tc a(1, 1); //val init tc b{ 1,1 }; //val init tc c = { 1,1 }; //val init tc d = tc{ 1,1 }; //val init cout << endl; tc* e = new tc[2]; //default init *2 cout << endl; tc* f = new tc[3]{ {1,1},{2,2},{3,3} }; //val init *3 cout << endl; tc* g = new tc[5]{ {1,1},{1} }; // val init + sing-val init + default init *3 cout << endl; cout << "testing return val of init_list\n"; tc h = makeObj(2, 2); //val init tc i = h; //copy init i = d; //copy assign i.printVal(cout); return 0; }
以下為運行截圖
列表初始化測試
添加initializer_list為參數(shù)的構(gòu)造函數(shù)后
testClass::testClass(initializer_list<int> list) :a(0), b(0) { int ab = 1; for (auto it = list.begin(); it != list.end(); it++) { if (ab) a += *it; else b += *it; } cout << "init_list init\n"; } int main() { tc a(1, 1); //val init tc b{ 1,1 }; //val init tc c = { 1,1 }; //val init tc d = tc{ 1,1 }; //val init cout << endl; tc* e = new tc[2]; //default init *2 cout << endl; tc* f = new tc[3]{ {1,1},{2,2},{3,3} }; //val init *3 cout << endl; tc* g = new tc[5]{ {1,1},{1} }; // val init + sing-val init + default init *3 cout << endl; cout << "testing return val of init_list\n"; tc h = makeObj(2, 2); //val init tc i = h; //copy init i = d; //copy assign i.printVal(cout); cout << endl; cout << "testing argument init_list\n"; tc j = { 1,2,3,4,5,6 }; tc k = { 9 }; return 0; }
以下為運行截圖
添加init_list后測試截圖
由此可見所有列表初始化都調(diào)用了含有initializer_list為參數(shù)的構(gòu)造函數(shù),證實了列表初始化是基于隱式轉(zhuǎn)換并以initializer_list為底層實現(xiàn)的構(gòu)想
應(yīng)用
- 在聲明時直接初始化堆上分配的對象(數(shù)組)
- 類:可以顯式指定使用的構(gòu)造函數(shù)(默認(rèn)會執(zhí)行無參數(shù)的構(gòu)造函數(shù))
- 內(nèi)置類型:可以在分配時直接指定值
- 在函數(shù)返回對象時避免自動存儲期對象銷毀的問題
- 手動調(diào)用std::initializer_list實現(xiàn)可變參數(shù)初始化
列表初始化防止類型收窄
C++11的列表初始化還有一個額外的功能就是可以防止類型收窄,也就是C++98/03中的隱式類型轉(zhuǎn)換,將范圍大的轉(zhuǎn)換為范圍小的表示,在C++98/03中類型收窄并不會編譯出錯,而在C++11中,使用列表初始化的類型收窄編譯將會報錯:
int a = 1.1; //OK int b{ 1.1 }; //error float f1 = 1e40; //OK float f2{ 1e40 }; //error const int x = 1024, y = 1; char c = x; //OK char d{ x };//error char e = y;//error char f{ y };//error
總結(jié)
列表初始化通過C++11引入的initializer_list容器實現(xiàn)了初始化方式的統(tǒng)一,可以看作一種語法糖
初始化類對象時,通過()調(diào)用構(gòu)造函數(shù)的地方都可以完全等價地用{}代替
={}不會生成臨時對象再拷貝初始化
到此這篇關(guān)于C++11中列表初始化機制的文章就介紹到這了,更多相關(guān)C++11列表初始化機制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++?BoostAsyncSocket實現(xiàn)異步反彈通信的案例詳解
這篇文章主要為大家詳細(xì)介紹了C++?BoostAsyncSocket如何實現(xiàn)異步反彈通信,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價值,感興趣的可以了解一下2023-03-03淺析C/C++ 中return *this和return this的區(qū)別
return *this返回的是當(dāng)前對象的克隆或者本身,return this返回當(dāng)前對象的地址,下面通過本文給大家介紹C/C++ 中return *this和return this的區(qū)別,感興趣的朋友一起看看吧2019-10-10C++實現(xiàn)關(guān)系與關(guān)系矩陣的代碼詳解
這篇文章主要介紹了C++實現(xiàn)關(guān)系與關(guān)系矩陣,功能實現(xiàn)包括關(guān)系的矩陣表示,關(guān)系的性質(zhì)判斷及關(guān)系的合成,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-04-04