C++的IO流與STL的空間配置器詳解
C++的IO流
在C++中,輸入數(shù)據(jù)和輸出數(shù)據(jù)用的是 cin >> 和 cout << ,cin的>>表示設(shè)備的數(shù)據(jù)流入對(duì)應(yīng)變量,cout的<<表示對(duì)應(yīng)變量數(shù)據(jù)流出到設(shè)備,因此這種輸入輸出的過(guò)程被形象的比喻為“流”。
istream/ostream
cin是標(biāo)準(zhǔn)庫(kù)中定義的istream類型的全局對(duì)象;cout是標(biāo)準(zhǔn)庫(kù)中定義的ostream類型的全局對(duì)象
iostream繼承了istream和ostream,因此用iostream實(shí)例化的對(duì)象可以輸入+輸出

它們調(diào)用的>>、<<本質(zhì)上是調(diào)用的operator>>()與operator<<()方法
int x; cin >> x; cin.operator>>(x);//與上面等價(jià) cout << x; cout.operator<<(x);//與上面等價(jià)
cout和cin不需要向C語(yǔ)言的scanf和printf一樣手動(dòng)指定類型,是因?yàn)閏in的>>,cout的<<對(duì)每個(gè)內(nèi)置類型都做了重載
int x;
while(cin >> x)
{
//
}對(duì)于上面代碼,可以保證有數(shù)據(jù)時(shí)一直循環(huán),當(dāng)輸入 Ctrl + Z (EOF標(biāo)志)時(shí)再跳出循環(huán),這本質(zhì)是得益于istream類重載的 operator bool 方法,允許流對(duì)象在布爾上下文中自動(dòng)轉(zhuǎn)換為bool值(istream的>>重載原本返回的是istream&類型)

ifstream/ofstream
ifstream 和 ofstream 是C++中用于文件IO流的兩個(gè)類,前者僅可以讀取,后者僅可以寫入,若想讀取+寫入可以用 fstream
//模式默認(rèn)是out,即以輸出模式打開
ofstream ofs("text.log"/*,ios::out*/);//fopen("text.log","w");
ofs << "eee";//向文件中寫入
ofs.close();//關(guān)閉文件
//模式默認(rèn)是in,即以輸入模式打開
string str;
ifstream ifs("text.log"/*,ios::in*/);//fopen("text.log",r);
ifs >> str;//讀取到str中
cout << str;若不在構(gòu)造函數(shù)中指定文件,也可以后續(xù)用 open() 方法
ofs.open("text.log"/*,ios::out*/);
ifs.open("text.log"/*,ios::in*/);需要注意的是,ofstream的<<只會(huì)寫入文本,例如ofs << 123,寫入的也是1,2,3的ASCII碼
而ofstream的 write() 方法可以寫入二進(jìn)制碼,例如ofs.write(123),寫入的是4字節(jié)二進(jìn)制值:0x7B 0x00 0x00 0x00(小端序)
ifstream的>>也只會(huì)讀取文本,若寫入時(shí)是以二進(jìn)制寫入,讀取也需要以二進(jìn)制讀取,可以用 read() 方法,但要用read讀取就必須在打開文件時(shí)指定模式 ios::binary ,表示以二進(jìn)制方式打開。
ifstream/ofstream的>>/<<的優(yōu)點(diǎn)就是,在想以字符串格式寫入數(shù)字型數(shù)據(jù)時(shí),不需要先把數(shù)字轉(zhuǎn)換成字符串(例如tostring())
info student("張三",20);
ofstream ofs("text.log");
ofs << student._name << endl;
ofs << student._age << endl;//不需要轉(zhuǎn)成字符串再傳入
ofs.close();
info s;
ifstream ifs("text.log");
ifs >> s._name;
ifs >> s._age;
cout << s._name << ' ' << s._age << endl;ps: fstream繼承自iostream,而iostream又繼承了ifstream和ofstream,因此fstream實(shí)例化的對(duì)象可讀可寫
istringstream/ostringstream
istringstream/ostringstream類用于將整型數(shù)據(jù)轉(zhuǎn)換為字符串(例如itoa(),tostring()等)或?qū)⒆址D(zhuǎn)換為對(duì)應(yīng)數(shù)據(jù)類型,前者可以從字符串中讀取數(shù)據(jù)(輸入流),常用于字符串解析和類型轉(zhuǎn)換,后者用于向字符串寫入數(shù)據(jù)(輸出流),常用于格式化拼接和類型轉(zhuǎn)換
若要將不同類型的數(shù)據(jù)都轉(zhuǎn)為字符串,就可以用 ostringstream 向字符串 寫入數(shù)據(jù)
若要將字符串再分割為基本類型,就可以用 istringstream
//序列化(轉(zhuǎn)換為字符串)
info student("張三",20);
ostringstream ost;
ost << student._name << endl;
ost << student._age << endl;
//反序列化(從字符串轉(zhuǎn)換為數(shù)據(jù))
info st;
istringstream ist;
ist.str(ost.str());
ist >> st._name >> st._age;
cout << st._name << ' ' << st._age << '\n';ps: stringstream繼承自iostream,而iostream又繼承了istringstream和ostringstream,因此stringstream是支持讀寫的雙向流,可解析可拼接
該對(duì)象常用于網(wǎng)絡(luò)字符串拼接與解析
空間配置器
STL的空間配置器簡(jiǎn)單來(lái)說(shuō)是內(nèi)存池,負(fù)責(zé)在容器申請(qǐng)內(nèi)存時(shí)分出內(nèi)存,這避免了頻繁申請(qǐng)內(nèi)存導(dǎo)致的效率開銷問(wèn)題??臻g配置器本質(zhì)也是以空間換時(shí)間的策略,因?yàn)槌鼗夹g(shù)的缺點(diǎn)就是不用時(shí)也會(huì)占用資源??臻g配置器分為一級(jí)空間配置器二級(jí)空間配置器
一級(jí)空間配置器
一級(jí)空間配置器就是malloc和free的封裝,并處理失敗拋異常機(jī)制。
在malloc開辟失敗時(shí),會(huì)先檢測(cè)使用者有無(wú)設(shè)置失敗的處理函數(shù)(一個(gè)函數(shù)指針),如果有就執(zhí)行,否則拋異常。默認(rèn)情況下沒有設(shè)置該失敗的函數(shù)指針句柄,即跟operator new基本一樣,失敗拋異常
要申請(qǐng)超過(guò)128字節(jié)的內(nèi)存時(shí),才會(huì)使用一級(jí)空間配置器,若在128字節(jié)以內(nèi),會(huì)用二級(jí)空間配置器
二級(jí)空間配置器
二級(jí)空間配置器即為內(nèi)存池

當(dāng)容器申請(qǐng)內(nèi)存時(shí),內(nèi)存池就分給容器對(duì)應(yīng)字節(jié)的內(nèi)存。但當(dāng)容器用完內(nèi)存時(shí),不能單獨(dú)釋放這一小塊內(nèi)存,當(dāng)時(shí)申請(qǐng)的多大內(nèi)存就要釋放多大內(nèi)存,為了管理這些用完的內(nèi)存,二級(jí)空間配置器加入了哈希桶(開散列)
索引以8字節(jié)為間隔,到128字節(jié),當(dāng)容器將內(nèi)存還回來(lái)時(shí),就會(huì)根據(jù)大小選擇掛在哪個(gè)索引下面,當(dāng)后續(xù)有容器想要申請(qǐng)內(nèi)存時(shí),就會(huì)先從哈希桶內(nèi)查找有無(wú)匹配的內(nèi)存

若容器申請(qǐng)的內(nèi)存在哈希桶中沒有,從內(nèi)存池中申請(qǐng)時(shí),也不會(huì)只切出對(duì)應(yīng)字節(jié)的內(nèi)存,而是直接切出20個(gè)該對(duì)象內(nèi)存,返回一個(gè),剩下19個(gè)掛在哈希桶下面。
由于容器申請(qǐng)的內(nèi)存一般都為小塊內(nèi)存,二級(jí)空間配置器就是專門為了解決申請(qǐng)小塊內(nèi)存而出現(xiàn)的,因此這樣做可以通過(guò)批量預(yù)分配顯著減少系統(tǒng)調(diào)用頻率,從而在頻繁申請(qǐng)小塊內(nèi)存的場(chǎng)景下提升性能
一個(gè)進(jìn)程中有一個(gè)空間配置器,進(jìn)程中所有的容器需要內(nèi)存,都會(huì)找空間配置器
內(nèi)存碎片問(wèn)題
內(nèi)碎片
在二級(jí)空間配置器中,如果申請(qǐng)的不是8字節(jié)的整數(shù)倍,也會(huì)向上內(nèi)存對(duì)齊到8字節(jié)整數(shù)倍,而這樣就會(huì)導(dǎo)致用于對(duì)齊的字節(jié)用不上,這就是內(nèi)碎片問(wèn)題
外碎片
當(dāng)在堆上開辟了多個(gè)小塊內(nèi)存后,若后續(xù)其中的幾塊內(nèi)存換回來(lái),也有可能不連續(xù)

紫色×表示已釋放,若此時(shí)再申請(qǐng)48字節(jié)內(nèi)存,即使我們之前釋放的空間也有48字節(jié),但不是連續(xù)的,就不能用這兩塊空間申請(qǐng),這就是外碎片問(wèn)題,因此對(duì)于STL容器(常申請(qǐng)小塊內(nèi)存),就有了空間配置器來(lái)管理內(nèi)存
內(nèi)核中針對(duì)大量小塊內(nèi)存申請(qǐng)的碎片化問(wèn)題,會(huì)使用slab分配器解決,它的結(jié)構(gòu)類似于二級(jí)空間配置器
既然內(nèi)核已經(jīng)有slab分配器管理小塊內(nèi)存,為什么STL還需要二級(jí)空間配置器?
- 內(nèi)核是針對(duì)整個(gè)系統(tǒng)的所有程序的,并且每個(gè)都去堆申請(qǐng),消耗特別大
- STL的容器需要的全是小塊內(nèi)存,而且需求大小集中,因此自己設(shè)計(jì)一個(gè)自己用會(huì)效率更高,順便解決內(nèi)存碎片問(wèn)題(解決了外碎片,但有內(nèi)碎片)
到此這篇關(guān)于C++的IO流與STL的空間配置器詳解的文章就介紹到這了,更多相關(guān)C++ IO流與STL空間配置器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺談C語(yǔ)言共用體和與結(jié)構(gòu)體的區(qū)別
下面小編就為大家?guī)?lái)一篇淺談C語(yǔ)言共用體和與結(jié)構(gòu)體的區(qū)別。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-02-02
C++實(shí)現(xiàn)判斷一個(gè)字符串是否為UTF8或GBK格式的方法
這篇文章主要介紹了C++實(shí)現(xiàn)判斷一個(gè)字符串是否為UTF8或GBK格式的方法,涉及C++針對(duì)字符編碼的遍歷、判斷、編碼轉(zhuǎn)換等相關(guān)操作技巧,需要的朋友可以參考下2017-11-11
c++回溯法解決1到9之間插入加減或空使運(yùn)算結(jié)果為100
編寫一個(gè)在1,2,…,9(順序不能變)數(shù)字之間插入+或-或什么都不插入,使得計(jì)算結(jié)果總是100的程序,并輸出所有的可能性。例如:1 + 2 + 34 – 5 + 67 – 8 + 9 = 1002021-10-10
初識(shí)C++的const關(guān)鍵字,常量與常變量
這篇文章主要為大家詳細(xì)介紹了C++的const關(guān)鍵字,常量與常變量,使用數(shù)據(jù)庫(kù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-03-03
C/C++ Zlib庫(kù)封裝MyZip壓縮類的詳細(xì)過(guò)程
在軟件開發(fā)中,文件的壓縮和解壓縮是一項(xiàng)常見的任務(wù),而ZIP是一種被廣泛應(yīng)用的壓縮格式,本文將聚焦于一個(gè)簡(jiǎn)化的C++實(shí)現(xiàn),通過(guò)分析代碼,我們將深入了解其設(shè)計(jì)和實(shí)現(xiàn)細(xì)節(jié),感興趣的朋友一起看看吧2023-11-11

