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

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

ifstream/ofstream
ifstream 和 ofstream 是C++中用于文件IO流的兩個類,前者僅可以讀取,后者僅可以寫入,若想讀取+寫入可以用 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的<<只會寫入文本,例如ofs << 123,寫入的也是1,2,3的ASCII碼
而ofstream的 write() 方法可以寫入二進(jìn)制碼,例如ofs.write(123),寫入的是4字節(jié)二進(jìn)制值:0x7B 0x00 0x00 0x00(小端序)
ifstream的>>也只會讀取文本,若寫入時是以二進(jìn)制寫入,讀取也需要以二進(jìn)制讀取,可以用 read() 方法,但要用read讀取就必須在打開文件時指定模式 ios::binary ,表示以二進(jìn)制方式打開。
ifstream/ofstream的>>/<<的優(yōu)點就是,在想以字符串格式寫入數(shù)字型數(shù)據(jù)時,不需要先把數(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實例化的對象可讀可寫
istringstream/ostringstream
istringstream/ostringstream類用于將整型數(shù)據(jù)轉(zhuǎn)換為字符串(例如itoa(),tostring()等)或?qū)⒆址D(zhuǎn)換為對應(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是支持讀寫的雙向流,可解析可拼接
該對象常用于網(wǎng)絡(luò)字符串拼接與解析
空間配置器
STL的空間配置器簡單來說是內(nèi)存池,負(fù)責(zé)在容器申請內(nèi)存時分出內(nèi)存,這避免了頻繁申請內(nèi)存導(dǎo)致的效率開銷問題。空間配置器本質(zhì)也是以空間換時間的策略,因為池化技術(shù)的缺點就是不用時也會占用資源??臻g配置器分為一級空間配置器二級空間配置器
一級空間配置器
一級空間配置器就是malloc和free的封裝,并處理失敗拋異常機(jī)制。
在malloc開辟失敗時,會先檢測使用者有無設(shè)置失敗的處理函數(shù)(一個函數(shù)指針),如果有就執(zhí)行,否則拋異常。默認(rèn)情況下沒有設(shè)置該失敗的函數(shù)指針句柄,即跟operator new基本一樣,失敗拋異常
要申請超過128字節(jié)的內(nèi)存時,才會使用一級空間配置器,若在128字節(jié)以內(nèi),會用二級空間配置器
二級空間配置器
二級空間配置器即為內(nèi)存池

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

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

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

