版權(quán)聲明:尊重原創(chuàng),轉(zhuǎn)載請(qǐng)注明來源。
目錄(?)[+]
昨天跟同事小小的研究了下關(guān)于不同平臺(tái)下的字節(jié)對(duì)齊問題,起因是遇到了一個(gè)坑,vs上沒有問題,在安卓上卻崩潰了。找了半天后發(fā)現(xiàn)是c++字節(jié)補(bǔ)齊問題,期間包括使用#PRagma pack(1)來限定字節(jié)對(duì)齊方式等各種條件,也是把我們搞的七暈八素,總算是進(jìn)一步了解了c++對(duì)象結(jié)構(gòu)以及編譯器的操作(有機(jī)會(huì)的話也補(bǔ)充下字節(jié)對(duì)齊的理解)。進(jìn)而想到了智能指針,稍微了解下。第一次接觸智能指針,天知道大學(xué)期間自己有多不努力,很多知識(shí)點(diǎn)都得留到現(xiàn)在來補(bǔ)齊,所以還是做做筆記吧。
簡(jiǎn)斷截說:c++的入門坑點(diǎn)大家都是有目共睹的,無非就是指針的理解不深導(dǎo)致一些野指針,內(nèi)存泄露等問題,所以就不贅述。智能指針正好能夠彌補(bǔ)這些問題,因?yàn)樗举|(zhì)是存放在棧的模板對(duì)象,只是在棧內(nèi)部包了一層指針。而棧在其生命周期結(jié)束時(shí),其中的指針指向的堆內(nèi)存也自然被釋放了。因而實(shí)現(xiàn)了智能管理的效果,不需要考慮內(nèi)存問題了,其實(shí)有點(diǎn)類似某種單例寫法,程序運(yùn)行結(jié)束,也不用考慮單例對(duì)象內(nèi)存問題。
本次討論:C++11之前的auto_ptr; c++11新加的unique_ptr, shared_ptr以及weak_ptr。
頭文件:#include <memory>
auto_ptr是我第一個(gè)看的智能指針,也是標(biāo)準(zhǔn)庫里的智能指針,有許多缺陷。
首先看下結(jié)構(gòu):
從圖中可以看書也是一個(gè)模板,使用方法大致類似于vector模板。如下:
[cpp] view plain copy從上圖可以看出,該智能指針成員函數(shù)也與vector相似,很容易得出
1、base1.get():返回當(dāng)前指針對(duì)象;
2、base1.release():清空當(dāng)前智能指針對(duì)象,并返回類型指針。所以假如我們要正常刪除,那么需要這樣:
[cpp] view plain copy3、base1.reset():從圖中可看出,是重置智能指針,即把內(nèi)存刪除,且智能指針指向空,但類型不變,所以可以這樣安全便捷地刪除:
[cpp] view%20plain copy然而繼續(xù)看,還有一個(gè)問題:auto_ptr還重載了等號(hào)操作符,由圖可知意思是把賦值智能指針的內(nèi)存交給被賦值智能指針,即如下意思:
介紹之前先上一張別人的表格,來源:http://my.oschina.net/hevakelcj/blog/465978,這是c++11中的智能指針與boost庫中的比較,原本boost就是為完善auto_ptr搞得這些,現(xiàn)在c++11有了,也就不需要再用咯。
2.unique_ptr
C++11引入了許多便捷的功能,其中也包括這個(gè),在用之前我們可以先看下底層:
可以清楚的看到,unique_ptr中的拷貝構(gòu)造和賦值操作符delete了,所以也就意味著,他和auto_ptr有區(qū)別,控制權(quán)唯一,不能隨意轉(zhuǎn)換。用法都差不多:
[cpp] view plain copyunique_ptr<Base1> base1(new Base1); unique_ptr<Base1> base2;//但是不能用拷貝構(gòu)造和等號(hào)賦值把base1賦值給base2了 但是如果想切換控制權(quán)的話也不是沒有辦法,我們可以看到還有個(gè)這樣的函數(shù):
要理解這兩個(gè)函數(shù),首先要理解c++11引入的move和forward;而要理解move和forward得先理解左值和右值概念。所以還是講全一點(diǎn)吧(已經(jīng)了解的就直接跳過可以):
補(bǔ)充知識(shí)點(diǎn)(其實(shí)可以直接看我下一篇更方便理解:點(diǎn)擊打開鏈接):
1、左值與右值:
左值指的是既能夠出現(xiàn)在等號(hào)左邊也能出現(xiàn)在等號(hào)右邊的變量(或表達(dá)式),右值指的則是只能出現(xiàn)在等號(hào)右邊的變量(或表達(dá)式)。需要注意的是,左值是指表達(dá)式結(jié)束后依然存在的持久對(duì)象,而右值是指表達(dá)式結(jié)束時(shí)就不再存在的臨時(shí)對(duì)象。T& 指向的是 lvalue,而 const T& 指向的,卻可能是 lvalue 或 rvalue,左值引用&與右值引用&&(右值引用是c++11加上的)。
2、move和forward:
需要明確的是,move函數(shù)可以是用于構(gòu)造函數(shù),也可以用于賦值函數(shù),但都需要手動(dòng)顯示添加。其實(shí)move函數(shù)用直白點(diǎn)的話來說就是省去拷貝構(gòu)造和賦值時(shí)中間的臨時(shí)對(duì)象,將資源的內(nèi)存從一個(gè)對(duì)象移動(dòng)到(共享也可以)另一個(gè)對(duì)象。官話是:c++11 中的 move() 是這樣一個(gè)函數(shù),它接受一個(gè)參數(shù),然后返回一個(gè)該參數(shù)對(duì)應(yīng)的右值引用。
std::forward<T>(u) 有兩個(gè)參數(shù):T 與 u。當(dāng)T為左值引用類型時(shí),u將被轉(zhuǎn)換為T類型的左值,否則u將被轉(zhuǎn)換為T類型右值。如此定義std::forward是為了在使用右值引用參數(shù)的函數(shù)模板中解決參數(shù)的完美轉(zhuǎn)發(fā)問題。
其實(shí)這里說的不夠清晰,下次翻譯一篇國外的解釋,閱讀下來就能很好理解move這個(gè)概念了,這里先不深入。
回到這張圖,這兩個(gè)函數(shù)體也就很明朗了——重載move版本的拷貝構(gòu)造函數(shù)以及重載move版本的等號(hào)賦值函數(shù)。
意思就是:把右值的對(duì)象(right)移動(dòng)給左值(_myt&),并且右值清空。
那么用法來了:
[cpp] view plain copyunique_ptr<Base1> base1(new Base1); unique_ptr<Base1> base2=move(base1);//base1變成empty unique_ptr<Base1> base3; base3 = move(base2);//base2變成empty 其它的成員函數(shù)就不一一贅述,和auto_ptr大致上是相同的。總結(jié),某種程度來說比auto_ptr更為安全,適用部分特殊情況。
3.shared_ptr
如果完全理解了上面兩個(gè)ptr的底層,那么shared_ptr的也就容易理解多了。但是和前兩者有很大區(qū)別——
前兩者控制權(quán)唯一,切換的時(shí)候把前面的清除。而shared_ptr不會(huì),照例看下底層:
很顯然,可以直接賦值和調(diào)用拷貝構(gòu)造函數(shù),且不會(huì)清空原本的智能指針。用法就很簡(jiǎn)單了:
[cpp] view plain copyshared_ptr<Base1> base1(new Base1); shared_ptr<Base1> base2=base1; shared_ptr<Base1> base3; base3 = base2;//三個(gè)共享一個(gè)
有個(gè)地方需要注意,當(dāng)刪除一個(gè)智能指針時(shí),并不影響其它兩個(gè)智能指針的繼續(xù)使用。因?yàn)樵撈瑑?nèi)存添加了一個(gè)引用計(jì)數(shù),每shared_ptr一次,引用計(jì)數(shù)+1;每次調(diào)用析構(gòu)函數(shù),引用計(jì)數(shù)減一。直到最后一個(gè)智能指針刪除,才會(huì)釋放內(nèi)存。
注意:
1、在繼續(xù)查看時(shí),你會(huì)發(fā)現(xiàn)以下兩個(gè)函數(shù):
其實(shí)就是和unique_ptr一樣可以通過move來切換控制權(quán),這個(gè)時(shí)候是切換,不是共享了。
2、接下來繼續(xù)翻看,還有兩個(gè)函數(shù):
(其實(shí)auto_ptr也有,只是一樣,沒必要截圖了)也就是說,auto_ptr和unique_ptr都可以通過move函數(shù)轉(zhuǎn)換成shared_ptr類型,當(dāng)然,一樣是切換控制權(quán)的形式,即舊的置空。
用法如下:
[cpp] view plain copyauto_ptr<Base1> base1(new Base1); shared_ptr<Base1> base2=move(base1);
4.weak_ptrred_ptr
weak_ptr更像是shared_ptr的助手:
1、他不像其余三種,可以通過構(gòu)造函數(shù)直接分配對(duì)象內(nèi)存;他必須通過shared_ptr來共享內(nèi)存。
2、沒有重載opreator*和->操作符,也就意味著即使分配到對(duì)象,他也沒法使用該對(duì)象
3、不主動(dòng)參與引用計(jì)數(shù),即,share_ptr釋放了,那么weak_ptr所存的對(duì)象也釋放了。
4、使用成員函數(shù)use_count()可以查看當(dāng)前引用計(jì)數(shù),expired()判斷引用計(jì)數(shù)是否為空。
5、lock()函數(shù),返回一個(gè)shared_ptr智能指針:
也就是讓weak_ptr觀測(cè)shared_ptr智能指針,并且在需要時(shí)候通過lock函數(shù)返回一個(gè)shared_ptr。
6、此外,百科上說:助手類enable_shared_from_this的Shared_from_this會(huì)返回this的shared_ptr,所以只需讓要被shared_ptr管理的類繼承它即可。我倒是沒試,有興趣的可以試試,大致意思也就是這般。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注