點(diǎn)擊上方“AI大道理”,選擇“置頂”公眾號 指針是一個變量,,其值為另一個變量的地址,即內(nèi)存位置的直接地址,。指針就像是一個目錄,,其值就像頁碼,頁碼指向某一個的內(nèi)容,。普通指針
C++沒有自動回收內(nèi)存的機(jī)制,,每次new出來的動態(tài)內(nèi)存必須手動delete。如果忘記delete,,資源未被釋放,,將導(dǎo)致內(nèi)存泄露。多個指針指向同一個對象時,,有一個指針釋放了,,但是其他指針并不知道這個情況,,若繼續(xù)使用那個被釋放的指針將出錯。問題3:野指針 沒有經(jīng)過初始化就直接拿來用的指針,,將出錯,。 智能指針智能指針是一個模板類,用來存儲指針(指向動態(tài)分配對象的指針),。智能指針是通過基本類型(模板類)指針構(gòu)造類的對象,,指針本身就是一個自定義的對象。當(dāng)此對象被銷毀時,,即調(diào)用此對象的析構(gòu)函數(shù),,釋放此指針。智能指針其實(shí)就是對普通指針的封裝,,封裝成一個類,。通過重載*和->兩個運(yùn)算符使得智能指針表現(xiàn)得就像普通指針一樣。能夠像指針一樣(運(yùn)算符重載,,解引用,指向?qū)ο蟪蓡T),。RAII思想(資源分配及初始化)(Resource Acquisition Is Initialization)- 構(gòu)造函數(shù)中完成資源的分配及初始化,。
- 析構(gòu)函數(shù)中完成資源的清理,可以保證資源的正確初始化和釋放
- 如果對象是用聲明的方式在棧上創(chuàng)建局部對象,,那么RAII機(jī)制就會正常工作,,當(dāng)離開作用域?qū)ο髸詣愉N毀而調(diào)用析構(gòu)函數(shù)釋放資源。
auto_ptr auto_ptr事實(shí)上是一個類,,在構(gòu)造對象時獲取對象的管理權(quán),,無需考慮釋放動態(tài)內(nèi)存開辟的空間,在析構(gòu)函數(shù)中直接釋放,,不會出現(xiàn)內(nèi)存泄漏的問題,。缺陷: 1)一個指針變量指向的空間不能由兩個auto_ptr管理,不然會析構(gòu)兩次,,使程序崩潰,。2)auto_ptr的拷貝構(gòu)造,將源指針的管理權(quán)交給目標(biāo)指針,,會使得源指針懸空,,解引用是會出現(xiàn)很多問題。 3)auto_ptr不能用來管理數(shù)組,,析構(gòu)函數(shù)中用的是delete,。 unique_ptrunique_ptr解決了auto_ptr編譯不報錯的問題,。unique_ptr是auto_ptr的繼承者,對于同一塊內(nèi)存只能有一個持有者,。 unique_ptr和auto_ptr唯一區(qū)別就是unique_ptr不允許賦值操作,,也就是不能放在等號的右邊,這一定程度避免了一些誤操作導(dǎo)致指針?biāo)袡?quán)轉(zhuǎn)移,。unique_ptr的核心特點(diǎn)就如它的名字一樣,,它擁有對持有對象的唯一所有權(quán),即兩個unique_ptr不能同時指向同一個對象,。nique_ptr所持有的對象只能通過轉(zhuǎn)移語義將所有權(quán)轉(zhuǎn)移到另外一個unique_ptr,。- release()釋放所管理指針的所有權(quán),,返回原生指針,。但并不銷毀原生指針。
- reset()釋放并銷毀原生指針,。如果參數(shù)為一個新指針,,將管理這個新指針
shared_ptrunique_ptr不能多個指針指向同一個資源,而shared_ptr可以,。每次復(fù)制或者多一個共享內(nèi)存資源的shared_ptr時,,計數(shù)+1;每次釋放shared_ptr時,,計數(shù)-1,;當(dāng)shared_ptr計數(shù)為0時,證明所有指向同一資源的shared_ptr都全部釋放了,。shared_ptr 需要維護(hù)的信息有兩部分: 常規(guī)的創(chuàng)建一個 shared_ptr: 為了構(gòu)建一個std::shared_ptr對象,,卻進(jìn)行了兩次內(nèi)存分配,,而且第二次內(nèi)存分配分配的內(nèi)存還比較小,這一方面會影響程序性能,,另一方面還會大大增加內(nèi)存碎片產(chǎn)生的可能性,。 復(fù)制一個 shared_ptr : std::make_shared創(chuàng)建一個 shared_ptr: std::make_shared的精妙之處就在于,它將std::shared_ptr構(gòu)造中的兩次內(nèi)存分配降低到了一次,。這會對提供程序性能和降低內(nèi)存碎片都有幫助,。 shared_ptr本身擁有的方法主要包括: reset() 釋放并銷毀原生指針,。如果參數(shù)為一個新指針,,將管理這個新指針 unique() 如果引用計數(shù)為 1,則返回 true,,否則返回 false use_count() 返回引用計數(shù)的大小
循環(huán)引用問題: 但是,,shared_ptr也有一個致命的缺點(diǎn),,就是會出現(xiàn)循環(huán)引用 Shared_ptr 會出現(xiàn)循環(huán)引用的情況:調(diào)用析構(gòu)后,還有互相引用的指針計數(shù)沒有減掉,。要釋放sp2,,就需要先釋放sp1->_next。要釋放sp1->_next,, 就需要先釋放sp1,。要釋放sp1,就需要先釋放sp2->_prev,。要釋放sp2->_prev,,就需要先釋放sp2。這樣一來,,就陷入了一個無限的循環(huán)當(dāng)中,,誰都釋放不掉。如何解決,?
weak_ptr std::weak_ptr 要與 std::shared_ptr 一起使用,。有時候我們只是想找個指向這塊內(nèi)存的指針,,但我們不想把這塊內(nèi)存的生命周期與這個指針關(guān)聯(lián),,這種情況下,弱引用指針就代表“我指向這東西,,但這東西什么時候釋放不關(guān)我事兒,。weak_ptr是輔助shared_ptr的存在,它只提供對管理對象的訪問手段,,同時可以實(shí)時動態(tài)知道所指向的對象是否存活,,起到觀察者的作用。 weak_ptr不具有普通指針的行為,,沒有重載operator *和->,只能想像旁觀者一樣觀測資源的使用情況。計數(shù)區(qū)域引進(jìn)新的計數(shù)變量weak_count,,來作為弱引用指針,。weak_ptr的構(gòu)造和析構(gòu)不會引起shared_ptr的計數(shù)的增加和減少,只會引起weak_count的增加和減少,。資源的釋放只取決shared的計數(shù),,當(dāng)計數(shù)為0時,釋放資源,,weak_ptr不控制資源的生命周期,。計數(shù)區(qū)域的釋放取決于shared計數(shù)和weak計數(shù),當(dāng)兩者都為0時,,才釋放計數(shù)區(qū)域,。weak_ptr本身擁有的方法主要包括: expired() 判斷所指向的原生指針是否被釋放,,如果被釋放了返回 true,否則返回 false use_count() 返回原生指針的引用計數(shù) lock() 返回 shared_ptr,,如果原生指針沒有被釋放,,則返回一個非空的 shared_ptr,否則返回一個空的 shared_ptr reset() 將本身置空
循環(huán)引用問題的解決: 調(diào)用析構(gòu)后,,sp1和sp2成功釋放,。要釋放sp1->_next, 就需要先釋放sp1,,已經(jīng)釋放,,所以sp1->_next釋放。要釋放sp2->_prev,,就需要先釋放sp2,,已經(jīng)釋放,所以sp2->_prev釋放,。總結(jié) unique_ptr:內(nèi)存的所有者或者說管理者必須是唯一的,。如果進(jìn)入不同的模塊或者調(diào)用者,,那么執(zhí)行所有權(quán)轉(zhuǎn)移。 shared_ptr: 內(nèi)存由多個指針變量共同使用,,共同擁有內(nèi)存的所有權(quán),。但是必須杜絕循環(huán)拷貝! weak_ptr: 對內(nèi)存的使用僅僅是訪問而已,,不涉及其生命周期的管理,。 —————— 掃描下方“AI大道理”,,選擇“關(guān)注”公眾號
|